Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8358506

WrongMethodTypeException thrown when return type is contextually discarded

XMLWordPrintable

      ADDITIONAL SYSTEM INFORMATION :
      All systems. OSs, Runtimes

      A DESCRIPTION OF THE PROBLEM :
      When calling MethodHandle.invokeExact() on a function with a non-void return type (e.g., int), but discarding the result (i.e., not assigning it or using it in an expression), the JVM throws a WrongMethodTypeException. The current exception message is wrong and misleading and implies a mismatch between the actual method handle type and the descriptor, even when the descriptor is correct.

      This issue occurs in the following context:

      MethodHandle handle = ...; // (MemorySegment, int, MemorySegment, MemorySegment)int
      handle.invokeExact(...); // Discards the return value
      This results in:

      WrongMethodTypeException: expected (MemorySegment, int, MemorySegment, MemorySegment)int but found (MemorySegment, int, MemorySegment, MemorySegment)void
      This is confusing and unhelpful, especially for users of the Foreign Function & Memory API, where correct signatures are critical and often auto-generated. It leads developers to waste time investigating what appears to be a descriptor mismatch with the native library when the problem is actually contextual (e.g., discarding a return value when a return type is expected).

      Recommended solution is to provide clearer description of this problem when detected in the Java invocation code and/or to provide an additional specific exception type for this particular case rather than throwing an incorrect exception.

      Expected Behavior / Enhancement Proposal:

      Improve the exception message to clarify that the problem is with the call site context, not the method handle’s type.

      Suggested message:
      WrongMethodTypeException: return type 'int' expected by MethodHandle, but result is unused in call site. Assign or use the return value to match method signature: (MemorySegment, int, MemorySegment, MemorySegment)int

      Alternately, detect this specific misuse and throw a different (more descriptive) exception, or add it as a footnote in the existing message.

      Justification:

      -Saves significant debugging time.
      -Avoids misleading developers into double-checking descriptors that are already correct.
      -Matches user expectations: function descriptor correctness should not depend on call-site context unless explicitly stated.

      *** This issue is particularly common with the Foreign Function & Memory API and affects early adopters and library maintainers.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Create a valid FunctionDescriptor for a native shared library function that returns a value.
      2. Create a MethodHandle from that FunctionDescriptor.
      3. Attempt to make the call using MethodHandle.invokeExact() without assigning the return value in the calling context.
      See code in the description.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The call should succeed with or without the return value being used in the calling context. However since the Java invocation design doesn't work this way, the attempt to call the function without assigning the return value in the calling context should throw a valid exception that identifies the problem rather than a invalid and misleading exception that describes a different problem.
      ACTUAL -
      The JVM throws a WrongMethodTypeException which is invalid. The method type is entirely correct and matches the FunctionDescriptor from which it was created. The function descriptor matches the shared native library function exactly as it is defined in the shared library.

      ---------- BEGIN SOURCE ----------
      Test case code is too complex to put here. It involves creating a shared native library with a function and then creating the Java FFM code to call it, and then creating the Java code to use the FFM MethodHandle to call the native function in a calling context where the return value of the native function is not assigned to anything.

      // C Code
      // Compile with: gcc -shared -fpic -o libadd.so libadd.c
      int add(int a, int b) {
          return a + b;
      }

      // Java Code
      import java.lang.foreign.*;
      import java.lang.invoke.*;

      public class FFMWrongMethodTypeDemo {
          public static void main(String[] args) throws Throwable {
              Linker linker = Linker.nativeLinker();
              SymbolLookup lookup = SymbolLookup.loaderLookup();

              FunctionDescriptor desc = FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.JAVA_INT, ValueLayout.JAVA_INT);
              MethodHandle addHandle = linker.downcallHandle(
                  lookup.find("add").orElseThrow(), desc
              );

              int a = 2, b = 3;

              // ✅ This works — the result is used
              int sum = (int) addHandle.invokeExact(a, b);
              System.out.println("Sum = " + sum);

              // ❌ This fails — the result is discarded
              // Throws: WrongMethodTypeException
              // Message: "expected (int,int)int but found (int,int)void"
              addHandle.invokeExact(a, b); // Result is ignored, causes exception
          }
      }

      # Compile C code
      gcc -shared -fpic -o libadd.so libadd.c

      # Compile Java code (Java 23+)
      javac --enable-preview --release 23 FFMWrongMethodTypeDemo.java

      # Run with preview features and shared lib
      java -Djava.library.path=. FFMWrongMethodTypeDemo

      // Output
      Sum = 5
      Exception in thread "main" java.lang.invoke.WrongMethodTypeException: expected (int,int)int but found (int,int)void
          at ...
      ---------- END SOURCE ----------

            pminborg Per-Ake Minborg
            webbuggrp Webbug Group
            Votes:
            1 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated: