This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit c68697c350c80e255248a0210bac2b109db72940 Author: opencode <[email protected]> AuthorDate: Sun Oct 11 22:02:23 2026 +0200 Harden RateLimiterBase.destroy() against a limiter whose configuration failed destroy() dereferenced bucketCounter unconditionally. That field is only assigned once newCounterInstance() returns, so a limiter whose setFilterConfig() failed part-way - for example a custom RateLimiter whose counter constructor rejected the configured duration, or an embedded caller driving the public RateLimiter API directly with an invalid duration - would throw a NullPointerException from destroy() instead of simply doing nothing, masking the original configuration failure. Skip the counter teardown when it was never created. The shutdown of internalExecutorService is a separate, already-guarded block and it still runs, which matters because the executor is assigned before the counter, so a failed setFilterConfig() that had created the internal executor still gets it shut down. Note that the standard filter lifecycle does not reach this case: an ApplicationFilterConfig whose init() threw is never registered, so the container never destroys that filter. This change hardens the public API for direct and embedded use. --- java/org/apache/catalina/util/RateLimiterBase.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/java/org/apache/catalina/util/RateLimiterBase.java b/java/org/apache/catalina/util/RateLimiterBase.java index 383def62b2..27930045d9 100644 --- a/java/org/apache/catalina/util/RateLimiterBase.java +++ b/java/org/apache/catalina/util/RateLimiterBase.java @@ -118,7 +118,11 @@ public abstract class RateLimiterBase implements RateLimiter { @Override public void destroy() { - bucketCounter.destroy(); + // bucketCounter remains null if setFilterConfig() failed before it was assigned, e.g. a counter + // constructor rejected the configured duration. Do not mask that failure with an NPE here. + if (bucketCounter != null) { + bucketCounter.destroy(); + } if (internalExecutorService != null) { try { internalExecutorService.shutdown(); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
