-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Class define support skips classes that are injected in system class loader #4248
Comments
The problem at hand is, what criteria do you use to select classes? A class is ultimately defined for a specific loader from a byte array with no explicit well-defined source. By excluding the known built-in loaders, we exclude the JDK and anything else on the class or module path which can reasonably be expected to be available on the class/module path of
The agent is thread-safe and can extend an existing configuration and if you observe anything different, it is a bug which we need to fix, but I suspect you mean something else. If you use agents in multiple processes in parallel and have them write to the same directory, the agents will overwrite each other's files. This is not something we can or should attempt to fix reliably on the agent level, instead whatever is using the agent this way needs to specify different directories and use |
To find a good algorithm we first need good examples. @lazar-mitrovic we need to collect different traces that lead to If there it is not decidable (or overly complicated) to see if a class is truly dynamically loaded, we can propose a modification to the JDK. |
I was just investigating a case where When a class is defined using a lookup they are injected into the corresponding classloader, and typically that's the system classloader :/ A minimal example: Class<?> clazz = (Class) MethodHandles.lookup().defineClass(CLASS_BYTES);
Object d = clazz.getDeclaredConstructor().newInstance(); |
I also encountered this problem. How can I get around it? Class<?> aClass = unloaded.load(nativeInterface.getClassLoader(), ClassLoadingStrategy.UsingLookup.of(lookup))
.getLoaded(); |
The only way to go around this is to perform this loading at image build time. The class predefinition is experimental and doesn't work in all the cases. |
At the moment our
experimental-class-define-support
agent option skips classes that are loaded in one of built-in class loaders.This poses an issue when running Scala's
LambdaDeserializer
as well as with any Mockito-related workload.I attached a Mockito/ByteBuddy reproducer based on one demo from aws-samples/serverless-graalvm-demo repository:
mockito-reproducer.zip
You can run it by invoking
bash run.sh
. This will run tests and produce agent output as well as dump of all ByteBuddy generated classes using its internalTypeWriter
. Output should look something like this:We can see that
ProductStore$MockitoMock.*
classes are missing from agent output. This is caused by Mockito trying to mock classes in same class loader as original class. Relevant code and comments:https://github.com/mockito/mockito/blob/faa6e92aec0c5b854c11422224e0628fa787a1cb/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java#L145-L175
Those classes then get filtered out in our
BreakpointInterceptor
'sonClassFileLoadHook
:graal/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/BreakpointInterceptor.java
Lines 1224 to 1228 in 83c37dd
Another potential issue is that AFAIK agent isn't additive nor thread safe, so if tests are being run in parallel, agent might overwrite old output. I'm not sure if this should be handled in agent or in
native-build-tools
though.cc: @peter-hofer @vjovanov
The text was updated successfully, but these errors were encountered: