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

Unexpected error code for one of the FFM guide example - macOS

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P4 P4
    • 24
    • None
    • docs
    • None
    • I ran this example on a Apple M1 Pro, OS version 14.7.1.

    • aarch64
    • os_x

      In here: https://docs.oracle.com/en/java/javase/23/core/checking-native-errors-using-errno.html.
      The example mentions errno 33 which makes totally sense in the context of a logarithmic function. However, after correcting the example (see JDK-8344242) and running it in jshell (same result is when I run through the IDE) with invokeLog(-1); the output is:

      jshell> invokeLog(-1)
      errno: 2
      errno string: No such file or directory
      $78 ==> NaN

      Code I provided to jshell:

      ```java
      import java.lang.foreign.*;
      import java.lang.invoke.*;
      import static java.lang.foreign.MemoryLayout.*;
          
      static double invokeLog(double v) throws Throwable {

              double result = Double.NaN;

              // Setup handles
              Linker.Option ccs = Linker.Option.captureCallState("errno");
              StructLayout capturedStateLayout = Linker.Option.captureStateLayout();
              VarHandle errnoHandle = capturedStateLayout.varHandle(PathElement.groupElement("errno"));

              // log C Standard Library function
              Linker linker = Linker.nativeLinker();
              SymbolLookup stdLib = linker.defaultLookup();
              MethodHandle log = linker.downcallHandle(
                      stdLib.find("log").orElseThrow(),
                      FunctionDescriptor.of(ValueLayout.JAVA_DOUBLE, ValueLayout.JAVA_DOUBLE),
                      ccs);

              // strerror C Standard Library function
              MethodHandle strerror = linker.downcallHandle(
                      stdLib.find("strerror").orElseThrow(),
                      FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.JAVA_INT));

              // Actual invocation
              try (Arena arena = Arena.ofConfined()) {
                  MemorySegment capturedState = arena.allocate(capturedStateLayout);

                  result = (double) log.invokeExact(capturedState, v);

                  if (Double.isNaN(result)) {
                      // Indicates that an error occurred per the documentation of
                      // the 'log' command.

                      // Get more information by consulting the value of errno:
                      int errno = (int) errnoHandle.get(capturedState, 0);
                      System.out.println("errno: " + errno);

                      // Convert errno code to a string message:
                      String errrorString = ((MemorySegment) strerror.invokeExact(errno))
                              .reinterpret(Long.MAX_VALUE).getString(0);
                      System.out.println("errno string: " + errrorString);
                  }
              }
              return result;
          }
      ```

      Same code ran on Linux (Raffaello Giulietti tried it):
      jshell> invokeLog(-1)
      errno: 33
      errno string: Numerical argument out of domain
      $5 ==> NaN

      The same errno behavior on macOS replicates for other math.h functions.
      My suggestion for the guide would be to provide an uniform example, that would use fopen function instead of math functions, but ultimately you know best.

      ```java
      import java.lang.foreign.*;
      import java.lang.invoke.*;
      import static java.lang.foreign.MemoryLayout.*;

      static void invokeFopen(String path, String mode) throws Throwable {

      // Setup handles
      Linker.Option ccs = Linker.Option.captureCallState("errno");
      StructLayout capturedStateLayout = Linker.Option.captureStateLayout();
      VarHandle errnoHandle = capturedStateLayout.varHandle(PathElement.groupElement("errno"));

      // log C Standard Library function
      Linker linker = Linker.nativeLinker();
      SymbolLookup stdLib = linker.defaultLookup();
      MethodHandle fopen =linker.downcallHandle(stdLib.find("fopen").orElseThrow(),
      FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS),
      ccs);

      // strerror C Standard Library function
      MethodHandle strerror = linker.downcallHandle(
      stdLib.find("strerror").orElseThrow(),
      FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.JAVA_INT));

      // Actual invocation
      try (Arena arena = Arena.ofConfined()) {
      MemorySegment capturedState = arena.allocate(capturedStateLayout);
      MemorySegment location = arena.allocateFrom(path);
      MemorySegment openMode = arena.allocateFrom(mode);

      var result = (MemorySegment) fopen.invokeExact(capturedState, location, openMode);

      if (result.address() == 0) {
      // Get more information by consulting the value of errno:
      int errno = (int) errnoHandle.get(capturedState, 0);
      System.out.println("errno: " + errno); // 2

      // Convert errno code to a string message:
      String errrorString = ((MemorySegment) strerror.invokeExact(errno))
      .reinterpret(Long.MAX_VALUE).getString(0);
      System.out.println("errno string: " + errrorString);
      }
      }
      }
      ```

            rgallard Raymond Gallardo
            amihalceanu Ana-Maria Mihalceanu
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: