premain: Crash in Infinispan server code caused by NPE under MethodHandleNative::linkDynamicConstant

Andrew Dinn adinn at redhat.com
Wed Sep 11 10:03:12 UTC 2024


Oops, sorry, I debugged this a few days ago! Correction to a few details:

On 11/09/2024 10:39, Andrew Dinn wrote:
> A crash due to an NPE was observed in the Infinispan (Data Grid) server 
> app when deployed using the Leyden EA. The crash still manifests with 
> the latest premain code. The crash happens below an application call 
> which employs a method reference as argument
> 
>          putMakedPasswordImplementations(this::putService, this);

The called method in turn calls consumer.accept

             consumer.accept(new Service(provider, 
PASSWORD_FACTORY_TYPE, algorithm, 
"org.wildfly.security.password.impl.PasswordFactorySpiImpl", emptyList, 
emptyMap));

which enters enters MethodHandleNative::linkDynamicConstant()

> Debugging shows that the call to linkDynamicConstant() returns null.
> 
> A simple reproducer for the problem is available as a maven project on 
> github:
> 
>    https://github.com/tristantarrant/elytron-leyden
> 
> The ReadMe provides an explanation of how to reproduce the problem. I 
> did so and the debugged to find out some of the details of what is 
> happening (see below) but did not fully clarify the problem. Help from 
> someone more conversant with the ins and outs of method handle 
> bootstraps in premain would be welcome. Details follow.
> 
> regards,
> 
> 
> Andrew Dinn
> -----------
> 
> I downloaded the git repo and attached the Java sources using Maven command
> 
>    $ mvn dependency:sources
> 
> Having manifested the crash by following the instructions in the README 
> I reran the leyden JVM under gdb using the following commands to enable 
> Java debugging
> 
> $ gdb ${LEYDEN_HOME}/bin/java
> (gdb) cd /path/to/mvn/project
> (gdb) run 
> -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 
> -classpath 
> /home/adinn/redhat/openjdk/infinispan/elytron-leyden/base/target/elytron-leyden-base-0.0.1-SNAPSHOT.jar:/home/adinn/.m2/repository/org/wildfly/security/wildfly-elytron-credential/2.5.1.Final/wildfly-elytron-credential-2.5.1.Final.jar:/home/adinn/.m2/repository/org/wildfly/security/wildfly-elytron-base/2.5.1.Final/wildfly-elytron-base-2.5.1.Final.jar -XX:CacheDataStore=elytron.aot com.redhat.leyden.Main
> 
> The problem manifests at WildflyElytronBaseProvider.java:112 in method 
> WildflyElytronBaseProvider::putMakedPasswordImplementations

     static void putMakedPasswordImplementations(Consumer<Service> 
consumer, Provider provider) {
         for (String algorithm : MASKED_ALGORITHMS) {
             consumer.accept(new Service(provider, 
PASSWORD_FACTORY_TYPE, algorithm, 
"org.wildfly.security.password.impl.PasswordFactorySpiImpl", emptyList, 
emptyMap)); <== NPE under this call
         }


> The source code for this method can be found in the following source jar
> 
> 
> ${M2_REPO}/org/wildfly/security/wildfly-elytron-base/2.5.1.Final/wildfly-elytron-base-2.5.1.Final-sources.jar
> 
> (where M2_REPO will normally be ~/.m2/repository)
> 
> Stepping into accept eventually enters MethodHandleNative::linkDynamicConstant 
> which in turn enters into ConstantBootstraps.makeConstant(). The caller 
> Class at this point is a lambda class which prints as 
> org.wildfly.security.WildflyElytronBaseProvider$$Lambda/0x800000000c
> 
> Several steps further the code enters BootstrapMethodInvoker::invoke 
> (below the app method call but via 3 hidden frames) with bootstrapMethod 
> bound to a DirectMethodHandle. After several more steps this enters 
> DirectMethodHandle$Holder.invokeStatic which in turn calls 
> MethodHandles::classData(Lookup,String,Class).
> 
> At this point caller is a MethodHandleLookup for the lambda class 
> Lambda/0x800000000c mentioned above. The following call
> 
>           Object classdata = classData(caller.lookupClass());
> 
> returns null to DirectMethodHandle$Holder.invokeStatic which pops the 
> same result back out to BootstrapMethodInvoker::invoke at line 90
> 
>                  if (type instanceof Class<?> c) {
>                      result = bootstrapMethod.invoke(caller, name, c); 
> <== null
> 
> This null result pops back out as the value for the call to 
> BootstrapMethodInvoker.invoke(), ConstantBootstraps.makeConstant() and 
> MethodHandleNative::linkDynamicConstant().
> 



More information about the leyden-dev mailing list