Not sure if I should report it here. We use a dynamic tracing tool to track the fine-grained data flow in SpringBoot applications. Generally, this tool will add wrapper methods for each existing method (even for methods in SpringBoot) via ASM. The wrapper methods use extra parameters to track the data dependence of original parameters. Unfortunately, this tool break SpringBoot applications (SpringBoot Version: 1.5.22), and we are trying to figure out the reason. The direct cause for the failure is that the bytecode of method createHealthIndicator
in class HealthIndicatorAutoConfiguration$DataSourcesHealthIndicatorConfiguration$$EnhancerBySpringCGLIB
does not pass the verification of JVM. More specifically, there is a invokevirtual
instruction for method <init>
, which should be called by invokespecial
instruction. Following is the stack trace of exception, the correct bytecode of the method when running without our dynamic tracing tool, and the wrong bytecode when running with our dynamic tracing tool.
Since the class is enhanced by Spring CGLib, we guess the logic of instrumentation of our dynamic tracing tool conflict with the Spring CGLib. Therefore, we want to know how Spring CGLib work on this class HealthIndicatorAutoConfiguration$DataSourcesHealthIndicatorConfiguration
.
Can anyone give me any hints on this?
Thanks!
Stack trace
Caused by: java.lang.VerifyError: (class: org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration$DataSourcesHealthIndicatorConfiguration$$EnhancerBySpringCGLIB$$d74fec9a, method: createHealthIndicator signature: (Ljava/lang/Object;)Lorg/springframework/boot/actuate/health/HealthIndicator;) Must call initializers using invokespecial
at java.lang.Throwable.fillInStackTrace$$PHOSPHORTAGGED(Throwable.java)
at java.lang.Throwable.fillInStackTrace$$PHOSPHORTAGGED(Throwable.java:784)
at java.lang.Throwable.<init>(Throwable.java:266)
at java.lang.Error.<init>(Error.java:70)
at java.lang.LinkageError.<init>(LinkageError.java:55)
at java.lang.VerifyError.<init>(VerifyError.java:53)
at java.lang.VerifyError.<init>(VerifyError.java)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName0$$PHOSPHORTAGGED(Class.java)
at java.lang.Class.forName$$PHOSPHORTAGGED(Class.java:348)
at org.springframework.cglib.core.ReflectUtils.defineClass$$PHOSPHORTAGGED(ReflectUtils.java:467)
at org.springframework.cglib.core.AbstractClassGenerator.generate$$PHOSPHORTAGGED(AbstractClassGenerator.java:336)
at org.springframework.cglib.proxy.Enhancer.generate$$PHOSPHORTAGGED(Enhancer.java:492)
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply$$PHOSPHORTAGGED(AbstractClassGenerator.java:93)
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply$$PHOSPHORTAGGED(AbstractClassGenerator.java:91)
at org.springframework.cglib.core.internal.LoadingCache$2.call$$PHOSPHORTAGGED(LoadingCache.java:54)
at java.util.concurrent.FutureTask.run$$PHOSPHORTAGGED(FutureTask.java:266)
at org.springframework.cglib.core.internal.LoadingCache.createEntry$$PHOSPHORTAGGED(LoadingCache.java:61)
... 32 more
Correct bytecode
protected final org.springframework.boot.actuate.health.HealthIndicator createHealthIndicator(java.lang.Object);
Code:
0: aload_0
1: aload_1
2: invokespecial #140 // Method org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration$DataSourcesHealthIndicatorConfiguration.createHealthIndicator:(Ljava/lang/Object;)Lorg/springframework/boot/actuate/health/HealthIndicator;
5: areturn
Wrong bytecode
protected final org.springframework.boot.actuate.health.HealthIndicator createHealthIndicator(java.lang.Object);
Code:
0: aload_0
1: invokevirtual #139 // Method "<init>":()V
4: checkcast #61 // class org/springframework/boot/actuate/health/HealthIndicator
7: areturn
Comment From: wilkinsona
Spring Boot 1.5 reached end of life last year and is no longer supported. Spring Boot 2.0.x is also out of support and 2.1.x is only supported until the end of October 2020. I'd recommend upgraded to Spring Boot 2.2 or, ideally, Spring Boot 2.3.
As of Spring Boot 2.2, its configuration classes are no longer proxied so upgraded should also address the problem described above. If you are interested in how @Configuration
classes are proxied, take a look at Spring Framework's ConfigurationClassEnhancer
.