ClassFile.build() is loading result file

Mark Roberts markro at cs.washington.edu
Wed Jan 8 02:13:03 UTC 2025


OK – I build my own version of java.base so I could debug this issue.  It
looks like the problem is that when StackMapGenerator wants to see if
something is an interface, the code ends up doing a Class.forName and loads
the class being built prematurely.



  Here is the interesting call stack:



  at
java.base/jdk.internal.loader.URLClassPath$FileLoader.getResource(URLClassPath.java:1073)

    at
java.base/jdk.internal.loader.URLClassPath.getResource(URLClassPath.java:315)

    at
java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:757)

    at
java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:681)

    at
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:639)

    at
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)

    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:528)

    at java.base/java.lang.Class.forName0(Native Method)

    at java.base/java.lang.Class.forName(Class.java:582)

    at java.base/java.lang.Class.forName(Class.java:561)

    at
java.base/jdk.internal.classfile.impl.ClassHierarchyImpl$ClassLoadingClassHierarchyResolver$1.apply(ClassHierarchyImpl.java:223)

    at
java.base/jdk.internal.classfile.impl.ClassHierarchyImpl$ClassLoadingClassHierarchyResolver$1.apply(ClassHierarchyImpl.java:219)

    at
java.base/jdk.internal.classfile.impl.ClassHierarchyImpl$ClassLoadingClassHierarchyResolver.getClassInfo(ClassHierarchyImpl.java:243)

    at
java.base/jdk.internal.classfile.impl.ClassHierarchyImpl$CachedClassHierarchyResolver$1.apply(ClassHierarchyImpl.java:134)

    at
java.base/jdk.internal.classfile.impl.ClassHierarchyImpl$CachedClassHierarchyResolver$1.apply(ClassHierarchyImpl.java:131)

    at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1229)

    at
java.base/jdk.internal.classfile.impl.ClassHierarchyImpl$CachedClassHierarchyResolver.getClassInfo(ClassHierarchyImpl.java:142)

    at
java.base/jdk.internal.classfile.impl.ClassHierarchyImpl.resolve(ClassHierarchyImpl.java:74)

    at
java.base/jdk.internal.classfile.impl.ClassHierarchyImpl.isInterface(ClassHierarchyImpl.java:86)

    at
java.base/jdk.internal.classfile.impl.StackMapGenerator$Type.mergeReferenceFrom(StackMapGenerator.java:1547)

    at
java.base/jdk.internal.classfile.impl.StackMapGenerator$Type.mergeFrom(StackMapGenerator.java:1515)

    at
java.base/jdk.internal.classfile.impl.StackMapGenerator$Frame.merge(StackMapGenerator.java:1376)

    at
java.base/jdk.internal.classfile.impl.StackMapGenerator$Frame.checkAssignableTo(StackMapGenerator.java:1326)

    at
java.base/jdk.internal.classfile.impl.StackMapGenerator.processMethod(StackMapGenerator.java:433)

    at
java.base/jdk.internal.classfile.impl.StackMapGenerator.generate(StackMapGenerator.java:302)

    at
java.base/jdk.internal.classfile.impl.StackMapGenerator.<init>(StackMapGenerator.java:245)

    at
java.base/jdk.internal.classfile.impl.StackMapGenerator.of(StackMapGenerator.java:156)

    at
java.base/jdk.internal.classfile.impl.DirectCodeBuilder$4.generateStackMaps(DirectCodeBuilder.java:317)

    at
java.base/jdk.internal.classfile.impl.DirectCodeBuilder$4.tryGenerateStackMaps(DirectCodeBuilder.java:325)

    at
java.base/jdk.internal.classfile.impl.DirectCodeBuilder$4.writeBody(DirectCodeBuilder.java:360)

    at
java.base/jdk.internal.classfile.impl.UnboundAttribute$AdHocAttribute.writeTo(UnboundAttribute.java:835)

    at
java.base/jdk.internal.classfile.impl.Util.writeAttribute(Util.java:230)

    at
java.base/jdk.internal.classfile.impl.AttributeHolder.writeTo(AttributeHolder.java:71)

    at
java.base/jdk.internal.classfile.impl.DirectMethodBuilder.writeTo(DirectMethodBuilder.java:146)

    at java.base/jdk.internal.classfile.impl.Util.writeList(Util.java:247)

    at
java.base/jdk.internal.classfile.impl.DirectClassBuilder.build(DirectClassBuilder.java:198)

    at
java.base/jdk.internal.classfile.impl.ClassFileImpl.build(ClassFileImpl.java:146)

    at java.base/java.lang.classfile.ClassFile.build(ClassFile.java:333)

    at daikon.chicory.Instrument.transform(Instrument.java:295)

    at
java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:259)

    at
java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)

    at
java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:611)

    at java.base/java.lang.ClassLoader.defineClass1(Native Method)

    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1026)

    at
java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)

    at
java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:862)

    at
java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:760)

    at
java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:681)

    at
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:639)

    at
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)

    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:528)

    at java.base/java.lang.ClassLoader.defineClass1(Native Method)

    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1026)

    at
java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)

    at
java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:862)

    at
java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:760)

    at
java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:681)

    at
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:639)

    at
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)

    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:528)

    at javautil.ArrayList17Test.main(ArrayList17Test.java:7)



Thank you,

Mark



*From:* Mark Roberts <markro at cs.washington.edu>
*Sent:* Monday, January 6, 2025 12:51 PM
*To:* 'Chen Liang' <liangchenblue at gmail.com>
*Cc:* 'classfile-api-dev' <classfile-api-dev at openjdk.org>
*Subject:* RE: ClassFile.build() is loading result file



I modified the jvmti minst tool to capture java execution method enter and
exit.  I have attached what I hope is the relevant part of the log file.
This section of the log file starts with:

daikon.chicory.Instrument.modifyClass exit

and ends with:

java.lang.LinkageError: loader 'app' attempted duplicate abstract class
definition for javautil.AbstractList17.



Along the way you can see the load:

 [6.689s][info][class,load] javautil.AbstractList17 source:
file:/scratch/markro/tests/scratch/markro/clones/mydaikon.24/tests/daikon-tests/ArrayList17/

Happening twice.  The second time is expected when the code exits the
transform method.  This first seems like an error that occurs at some point
while the DirectCodeBuilder is running.



Hope this helps to debug my problem.



Thank you,

Mark





*From:* Chen Liang <liangchenblue at gmail.com>
*Sent:* Sunday, January 5, 2025 2:06 PM
*To:* Mark Roberts <markro at cs.washington.edu>
*Cc:* classfile-api-dev <classfile-api-dev at openjdk.org>
*Subject:* Re: ClassFile.build() is loading result file



Hi Mark,
why do you need to supply the ClassLoader to the modifyClass method? Class
file transformation should have no dependency on the CHA process, and the
only need is encapsulated within the ClassFile context object.

Can you post your modifyClass?

Chen



On Sun, Jan 5, 2025, 2:57 PM Mark Roberts <markro at cs.washington.edu> wrote:

I am using ClassFileTransformer.transform() to instrument class files as
they are loaded.   Within my transform method I call



byte[] newBytes =  classFile.build(classModel.thisClass().asSymbol(),

                          classBuilder -> modifyClass(classBuilder,
classModel, loader));



where modifyClass does all the instrumentation.



The problem is some where inside of classFile.build() the class is actually
being loaded!  Thus, when I return newBytes from the transform method I get
an error ‘attempted duplicate abstract class definition’. I have verified
that the class has not be loaded prior to the return from modifyClass().



What is going on?



Thank you,

Mark
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/classfile-api-dev/attachments/20250107/48abd8a6/attachment-0001.htm>


More information about the classfile-api-dev mailing list