BlockHound.install() fails with NPE on jdk17 if application is started as java module
dvoloshyn opened this issue · comments
BlockHound.install();
makes jvm exit because of unhandled exception: dynamicThreadPredicate
is null
.
Steps to Reproduce
- Use Oracle JDK 17,
- Create spring-boot application
- Add
module-info.java
with required dependencies - Use
spring-boot-starter-log4j2:2.5.5
anddisruptor:3.4.4
- Use the following VM options:
-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector -XX:+AllowRedefinitionToAddDeleteMethods
- execute
BlockHound.install();
inside thestatic {}
section of the main class - Put breakpoint into
BlockHoundRuntime:62
and run the application from Intellij IDEA - Breakpoint will be hit with the following stacktrace:
"Log4j2-TF-1-AsyncLogger[AsyncContext@340f438e]-1@2177" daemon prio=5 tid=0x13 nid=NA runnable
java.lang.Thread.State: RUNNABLE
at reactor.blockhound.BlockHoundRuntime.lambda$static$0(BlockHoundRuntime.java:62)
at reactor.blockhound.BlockHoundRuntime$$Lambda$247/0x0000000800c64260.get(Unknown Source:-1)
at java.lang.ThreadLocal$SuppliedThreadLocal.initialValue(ThreadLocal.java:305)
at java.lang.ThreadLocal.setInitialValue(ThreadLocal.java:195)
at java.lang.ThreadLocal.get(ThreadLocal.java:172)
at reactor.blockhound.BlockHoundRuntime.checkBlocking(BlockHoundRuntime.java:78)
at jdk.internal.misc.Unsafe.park(Unsafe.java:-1)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:252)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:1672)
at com.lmax.disruptor.TimeoutBlockingWaitStrategy.waitFor(TimeoutBlockingWaitStrategy.java:38)
at com.lmax.disruptor.ProcessingSequenceBarrier.waitFor(ProcessingSequenceBarrier.java:56)
at com.lmax.disruptor.BatchEventProcessor.processEvents(BatchEventProcessor.java:159)
at com.lmax.disruptor.BatchEventProcessor.run(BatchEventProcessor.java:125)
at java.lang.Thread.run(Thread.java:833)
- Observe that field
dynamicThreadPredicate
isnull
. Resuming results in NPE
Your Environment
reactor 3.4.10
blockhound 1.0.6.RELEASE
Windows 10
java 17 2021-09-14 LTS
Java(TM) SE Runtime Environment (build 17+35-LTS-2724)
Java HotSpot(TM) 64-Bit Server VM (build 17+35-LTS-2724, mixed mode, sharing)
Side note found while reproducing: for the agent to attach, here is the module-info.java
that I ended up with:
module blockhoundNpe.main {
requires jdk.attach; //required for bytebuddy to attach
requires jdk.unsupported; //required for Unsafe access by log4j
requires reactor.blockhound;
requires spring.boot;
requires spring.boot.autoconfigure;
}
Otherwise, an IllegalStateException: No compatible attachment provider is available
is thrown by bytebuddy.
I'll need @bsideup's expertise here. It looks like with modules there is either an issue with BlockHoundRuntime
being loaded outside the bootstrap classloader, or some initialization change that leads to out-of-order usage vs loading of blockhound...
In any case, BlockhoundRuntime.STATE.withInitial
block sees null
values for the predicates and the blockingMethodConsumer
.
I tried to give these default values, but that renders Blockhound#testInstrumentation
non-functional 😞
I met the same issue in open JDK 11. Anyone can support it or fix it? It looks the BlockHound community is inactive now.
0 = {StackTraceElement@3075} "reactor.blockhound.BlockHoundRuntime.lambda$static$0(BlockHoundRuntime.java:62)"
1 = {StackTraceElement@3076} "java.base/java.lang.ThreadLocal$SuppliedThreadLocal.initialValue(ThreadLocal.java:305)"
2 = {StackTraceElement@3077} "java.base/java.lang.ThreadLocal.setInitialValue(ThreadLocal.java:195)"
3 = {StackTraceElement@3078} "java.base/java.lang.ThreadLocal.get(ThreadLocal.java:172)"
4 = {StackTraceElement@3079} "java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)"
5 = {StackTraceElement@3080} "reactor.blockhound.TestThread.(TestThread.java:29)"
6 = {StackTraceElement@3081} "reactor.blockhound.BlockHound$Builder.testInstrumentation(BlockHound.java:462)"
7 = {StackTraceElement@3082} "reactor.blockhound.BlockHound$Builder.install(BlockHound.java:445)"
8 = {StackTraceElement@3083} "reactor.blockhound.BlockHound.install(BlockHound.java:95)"
it seems that there is a work around: since #297, we can now start the blockhound agent using the jvm option -javaagent
, which seems to work well in jpms. You don't need to call BlockHound.install()
from the code, just start the jvm with the -javaagent:; and blockhound will even be able to locate BlockHoundIntegration plugins declared inside modules (named, un-named, or automatic modules), because ServiceLoader also locates SPIs from modules.
I'm attaching a sample project (see README.MD file), which is using reactor-netty in a jpms environment:
I'm closing this issue because there is a work around (see previous posted sample demo project).
Feel free to reopen if needed.