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 (seeJDK-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);
}
}
}
```
The example mentions errno 33 which makes totally sense in the context of a logarithmic function. However, after correcting the example (see
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);
}
}
}
```