-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
Hello everyone.
My name is Michael, I work for Neo4j and I contributed the Neo4j extension to the Quarkus project. That extension worked nicely in native mode and stopped doing so since Quarkus upgraded to GraalVM 19.3 (See related issue here quarkusio/quarkus#6115).
A little background to our driver: We shade Netty and have some substitutions in place to make SSL and some reflections work, which you can find here:
- https://github.com/neo4j/neo4j-java-driver/tree/4.0.0/driver/src/main/resources/META-INF/native-image/org.neo4j/driver
- https://github.com/neo4j/neo4j-java-driver/tree/4.0.0/driver/src/main/java/org/neo4j/driver/internal/svm
The bug happens when the driver receives a message from the server in a pack stream format. I have a fully runnable example here https://github.com/michael-simons/neo4j-java-driver-native-example, but you need to have a running Neo4j instance to make use of it.
I was however able to pin point our issue to the code inside Unpacker
, which you find here: https://github.com/neo4j/neo4j-java-driver/blob/4.0.0/driver/src/main/java/org/neo4j/driver/internal/packstream/PackStream.java#L401
In GraalVM prior to 19.3, regardless of -H:Optimize=n
settings, the GraalVM native image compiler produced working code. Since 19.3, the various methods, and I think the partial switch statements, seem to fold into one which lead to wrong exceptions.
You'll find attached a reproducer, that doesn't need a running Neo4j instance. It's only dependency is io.netty:netty-buffer
and I create the scenario when the message handler receives a welcome message from our server. The class optimizationissue.Reproducer
creates a Netty ByteBuf
from the message that the server sent and decodes it as the original Neo4j driver would do. It uses a copy of PackStream$Unpacker
that I linked above.
The message starts with a struct header, so we start by calling optimizationissue.PackStream.Unpacker#unpackStructHeader
. And while the message fit's a struct header, some other branch seems to be called.
The expected output is {server=Neo4j/4.0.0-rc01, connection_id=bolt-536}
.
If you add -H:Optimize=0
to the native image generation, things work as expected.
Find the complete project attached and thanks for looking into this.