Describe the bug
(Note: This vulnerability was identified via Static Program Analysis.)
There is a severe ClassLoader leak risk (ClassLoader Pinning / Metaspace OOM) caused by the use of anonymous inner classes for ThreadLocal initialization in com.timgroup.statsd.NonBlockingStatsDClient.
The Root Cause:
Around line 117, NUMBER_FORMATTER and SAMPLE_RATE_FORMATTER are instantiated using anonymous inner classes:
protected static final ThreadLocal<NumberFormat> NUMBER_FORMATTER =
new ThreadLocal<NumberFormat>() {
@Override
protected NumberFormat initialValue() {
return newFormatter(false);
}
};
When compiled, this generates an anonymous subclass (e.g., NonBlockingStatsDClient$1.class). In a Web Container environment (like Tomcat or Jetty), this anonymous class is loaded by the application's WebappClassLoader.
The Impact:
StatsD clients are typically executed by the web container's core worker threads (e.g., http-nio-exec), which are long-lived and created by a parent ClassLoader. The worker thread's ThreadLocalMap will hold a reference to the instance of this anonymous class.
When the web application is stopped or hot-redeployed, the worker threads remain alive. Because the thread holds a reference to the anonymous class instance, and the instance holds a reference to its defining WebappClassLoader, the entire ClassLoader (and all classes/statics loaded by it) cannot be garbage collected. Multiple redeployments will inevitably lead to a java.lang.OutOfMemoryError: Metaspace or PermGen space.
Suggested Fix
If this project supports Java 8+, the fix is highly straightforward. Replace the anonymous inner classes with ThreadLocal.withInitial().
protected static final ThreadLocal<NumberFormat> NUMBER_FORMATTER =
ThreadLocal.withInitial(() -> newFormatter(false));
protected static final ThreadLocal<NumberFormat> SAMPLE_RATE_FORMATTER =
ThreadLocal.withInitial(() -> newFormatter(true));
Why this works: ThreadLocal.withInitial() returns a standard SuppliedThreadLocal which is loaded by the Bootstrap ClassLoader. This completely severs the strong reference chain to the WebappClassLoader, resolving the leak natively.
Describe the bug
(Note: This vulnerability was identified via Static Program Analysis.)
There is a severe ClassLoader leak risk (ClassLoader Pinning / Metaspace OOM) caused by the use of anonymous inner classes for
ThreadLocalinitialization incom.timgroup.statsd.NonBlockingStatsDClient.The Root Cause:
Around line 117,
NUMBER_FORMATTERandSAMPLE_RATE_FORMATTERare instantiated using anonymous inner classes: