You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the issue
For clarity, I refer the original class to be substituted as target class, and the substitution class annotated with @TargetClass as substitution class.
Current class initialization attempts to initialize the target class at build time, which is unnecessary and causes initialization errors.
Current initialization process firstly initializes all unconfigured classes as safe, and then checks whether the class is safe in method com.oracle.svm.hosted.classinitialization.TypeInitializerGraph.tryPromoteToUnsafe:
type.getClassInitializer() here gets the wrapped type's initializer which is actually the substitution class' initializer.
However, at last when the method com.oracle.svm.hosted.classinitialization.ClassInitializationFeature.initializeSafeDelayedClasses initializes the safe classes, it initializes the class c which is actually the target class.
The problem to initialize a class with substitution is the class under safety checking and initialization are inconsistency. Therefore, if the substitution class is safe but the target class is not, the initialization will lead to build time errors. Actually when the class is substituted with @Substitute or @Delete, the target class will never appear at runtime, and it's not necessary to initialize it at build time at all.
Steps to reproduce the issue
This issue was discovered from a realistic application using log4j, and can be reproduced with the attached simplified test: testClinit.zip
Unzip testClinit.zip
Edit clinitTest.sh to set GRAALVM_CP to GRAALVM_CP_8 or GRAALVM_CP_11 according to your own environment.
Run clinitTest.sh and it fails with the follows messges:
To see how the classes got initialized, use --trace-class-initialization=org.apache.logging.log4j.util.LoaderUtil,org.apache.logging.log4j.util.PropertiesUtil
[com.alibaba.test.clinittest:77312] write: 198.52 ms, 2.35 GB
Error: Classes that should be initialized at run time got initialized during image building:
org.apache.logging.log4j.util.LoaderUtil was unintentionally initialized at build time. To see why org.apache.logging.log4j.util.LoaderUtil got initialized use --trace-class-initialization=org.apache.logging.log4j.util.LoaderUtil
org.apache.logging.log4j.util.PropertiesUtil was unintentionally initialized at build time. To see why org.apache.logging.log4j.util.PropertiesUtil got initialized use --trace-class-initialization=org.apache.logging.log4j.util.PropertiesUtil
com.oracle.svm.core.util.UserError$UserException: Classes that should be initialized at run time got initialized during image building:
org.apache.logging.log4j.util.LoaderUtil was unintentionally initialized at build time. To see why org.apache.logging.log4j.util.LoaderUtil got initialized use --trace-class-initialization=org.apache.logging.log4j.util.LoaderUtil
org.apache.logging.log4j.util.PropertiesUtil was unintentionally initialized at build time. To see why org.apache.logging.log4j.util.PropertiesUtil got initialized use --trace-class-initialization=org.apache.logging.log4j.util.PropertiesUtil
Describe the issue
For clarity, I refer the original class to be substituted as target class, and the substitution class annotated with
@TargetClass
as substitution class.Current class initialization attempts to initialize the target class at build time, which is unnecessary and causes initialization errors.
Current initialization process firstly initializes all unconfigured classes as safe, and then checks whether the class is safe in method
com.oracle.svm.hosted.classinitialization.TypeInitializerGraph.tryPromoteToUnsafe
:type.getClassInitializer()
here gets the wrapped type's initializer which is actually the substitution class' initializer.However, at last when the method
com.oracle.svm.hosted.classinitialization.ClassInitializationFeature.initializeSafeDelayedClasses
initializes the safe classes, it initializes the classc
which is actually the target class.The problem to initialize a class with substitution is the class under safety checking and initialization are inconsistency. Therefore, if the substitution class is safe but the target class is not, the initialization will lead to build time errors. Actually when the class is substituted with
@Substitute
or@Delete
, the target class will never appear at runtime, and it's not necessary to initialize it at build time at all.A patch to fix this issue is proposed: #2935
Steps to reproduce the issue
This issue was discovered from a realistic application using log4j, and can be reproduced with the attached simplified test:
testClinit.zip
GRAALVM_CP
toGRAALVM_CP_8
orGRAALVM_CP_11
according to your own environment.Describe GraalVM and your environment:
The text was updated successfully, but these errors were encountered: