This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 11.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit dc8fce01dd292ed46b99151ec25abf27751ae827 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 fd1c9289fc..c45b007614 100644 --- a/java/org/apache/jasper/runtime/JspFactoryImpl.java +++ b/java/org/apache/jasper/runtime/JspFactoryImpl.java @@ -42,7 +42,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, @@ -81,7 +81,14 @@ public class JspFactoryImpl extends JspFactory { 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]
