-
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
Exception handling not working correctly in native-image master with --allow-incomplete-classpath #812
Comments
Thanks for reporting and for the easy to use reproducer. The issue is now fixed in master. However, now I run into another runtime error:
Everything seems to run ok when I run |
@cstancu Thanks, I will look into it. Maybe it because the bean for |
@cstancu I updated the example to use a minimal So it is definitely not the reflect.json that is the issue. I am wondering if there is a bug in the |
You are right, it looks like we are registering the For now, just removing
|
Interesting, so looks like we can probably get rid of Regarding the I think somehow Graal is reporting |
This is the code that is failing, it should be reporting the classes as missing on the class path (which they are): Instead the log doesn't output any It seems there is still something wrong with the
What should happen is the string constructor should be used, but instead it seems the class constructor is used even if the class is not there? |
@cstancu @thomaswue I have looked into this further to try and identify the problem and it seems at image compilation time Graal is representing classes that are not present as being present. I added some printlns to this constructor (which should never be invoked as the class is not present): diff --git a/core/src/main/java/io/micronaut/core/annotation/AnnotationClassValue.java b/core/src/main/java/io/micronaut/core/annotation/AnnotationClassValue.java
index 739d51549..2db7d7081 100644
--- a/core/src/main/java/io/micronaut/core/annotation/AnnotationClassValue.java
+++ b/core/src/main/java/io/micronaut/core/annotation/AnnotationClassValue.java
@@ -42,6 +42,7 @@ public final class AnnotationClassValue<T> implements CharSequence, Named {
*/
@UsedByGeneratedCode
public AnnotationClassValue(String name) {
+ System.out.println("name = " + name);
this.name = name.intern();
this.theClass = null;
}
@@ -53,6 +54,7 @@ public final class AnnotationClassValue<T> implements CharSequence, Named {
*/
@UsedByGeneratedCode
public AnnotationClassValue(Class<T> theClass) {
+ System.out.println("theClass = " + theClass);
this.name = theClass.getName().intern();
this.theClass = theClass;
} At image compilation time I see output like from the println like:
However the output should be:
The constructor that takes a class reference should never be invoked because the class is not there, but somehow the incorrect constructor is being invoked for code like this: AnnotationClassValue $micronaut_load_class_value_0() {
try {
// should not be invoked
return new AnnotationClassValue(reactor.core.publisher.Mono.class);
} catch(Throwable e) {
// exception should cause this constructor to be invoked
return new AnnotationClassValue("reactor.core.publisher.Mono");
}
} This indicates that GraalVM native image tool thinks the class is there, but in fact it is not there. When I then run the application this is resulting in false positives at runtime and breaking the application. Could you explain why or provide a solution to why GraalVM native image is returning class references when these class references are not on the class path? |
When Now, I am concerned with why and how this example fails at runtime? The snippet you provided should behave exactly the same on HotSpot as on SVM in case Is there a way to reproduce the runtime failure? |
@vjovanov The example in the issue report has been updated with steps to reproduce https://github.com/graemerocher/micronaut-graal-experiments/tree/master/fresh-graal Simply clone it run
This should never happen because there are checks in the real code for the existence of the class |
@vjovanov What appears to be happening is that code run in static initialisers that reference classes not on the class path is not executed again at runtime, this results in the app thinking the classes are there at runtime. Why are these ghost classes loadable from the class loader? Surely that would break all static initialisers that do class loading? |
True, this is the bug that we are hitting here; thanks for figuring it out. I am working on a fix now and I can see that wrong decisions are made during static initialization based on ghost classes. Unfortunately, I can't reproduce the issue on GraalVM running on OS X. When I follow the instructions I get:
|
@vjovanov I have pushed a fix for that, sorry it was a duplication of the classes in META-INF/services |
@graemerocher thank you for your patience! I made some progress on this, the changes will be merged into master soon. Using mock-up classes, i.e., the so called ghost classes, to model the missing classes turned out to be problematic because they could leak into the executable, so I completely removed that idea and reimplemented our support for code that references missing types. Now the example program executes past the previous step. However, it chockes later with:
After some debugging I figured out that the method for which this fails is It could have something to do with annotations that reference missing types, but I am not sure. I am currently trying to understand how micronaut processes annotations, especially in the context of https://bugs.openjdk.java.net/browse/JDK-7183985 which could be triggered for example by |
@cstancu I am going to build from master and try reproduce to get back to you. Micronaut doesn't use the annotation API from Java directly, it computes annotation metadata at compilation time so that it can deal with merging meta annotations, referencing classes not present etc. The most likely cause of this problem is is the code is arriving here https://github.com/micronaut-projects/micronaut-core/blob/bde43d75b1848ab14c170cf79606e3e1471e7eba/core/src/main/java/io/micronaut/core/annotation/AnnotationMetadata.java#L325 Which triggers a |
@cstancu I found a place where we were still doing And updated the example at https://github.com/graemerocher/micronaut-graal-experiments/tree/master/fresh-graal (you can do However I have not been able to test if the change is working with the master version of GraalVM, I guess as you said you have not yet pushed the changes. |
Related issue #851 |
Thanks @graemerocher. |
@graemerocher my changes are now merged (see 39b9b49) and with your latest update I was able to successfully build a working image. Accessing |
Fantastic news!! Thanks! |
Did this change make it into rc10? I am seeing the same behaviour as in this comment Which indicates the ghost class issue is still present? |
Ah no, I see RC10 was released earlier, so this will be in RC11. Do you have a release date yet? |
Hi @graemerocher, we do not have an official release date, but ideally RC11 will be available at some point next week. |
Good news! |
btw we have now released 1.0.3 of Micronaut so the integration test @cstancu added can be updated to use a non-snapshot version |
@graemerocher thanks for the heads up! |
Steps to reproduce using GraalVM master:
git clone git@github.com:graemerocher/micronaut-graal-experiments.git
cd fresh-graal
build-native-image.sh
The image builds but when starting the app the exception is thrown:
The exception originates from generated byte code, that looks like
The exception should hence never be thrown and be caught and handled. This worked fine in rc8.
The text was updated successfully, but these errors were encountered: