Segmentation fault with new Linker.Option.CaptureCallState feature
Mark Schroeder
mark.schroeder at tu-dortmund.de
Fri Nov 18 21:09:06 UTC 2022
Hi Jorn,
Thank you so much for fixing this!
I also tested the change with my own code and it worked perfectly (just
for context, I used the recvmsg system call, which returns -1 and sets
errno to EAGAIN if there is no data available on a nonblocking socket).
Best regards,
Mark
On 2022-11-17 19:43, Jorn Vernee wrote:
> Hi,
>
> I've found the issue(s) and submitted a PR here:
> https://github.com/openjdk/panama-foreign/pull/753
>
> We'll probably to get this into JDK20 as well.
>
> Thanks for reporting!
>
> Jorn
>
> On 15/11/2022 01:02, Maurizio Cimadamore wrote:
>> Hi Mark,
>> many thanks for the bug report (and the kind words :-) ).
>>
>> This looks like a bug - in the sense that I'm not aware of any
>> limitations in this area. The fact that the function returns a value
>> must be tripping something up in the assembly trampoline we generate.
>>
>> For now, I've filed this:
>>
>> https://bugs.openjdk.org/browse/JDK-8296973
>>
>> Thanks!
>> Maurizio
>>
>> On 14/11/2022 21:56, Mark Schroeder wrote:
>>> Hi everyone,
>>>
>>> first of all, I wanted to thank you for the amazing work you're doing
>>> in this project. I really enjoy working with the API.
>>> While experimenting with some system calls under Linux, I encountered
>>> an issue with the new Linker.Option.CaptureCallState feature
>>> delivered here: https://github.com/openjdk/panama-foreign/pull/742.
>>> When calling a function that returns a value (such as a system call
>>> returning -1 in case of an error), the JVM exits due to a
>>> segmentation fault. As a minimal example, I adapted the test code
>>> from the pull request (the issue is not limited to system calls).
>>> This is the C code:
>>>
>>> #include <errno.h>
>>> #include <stdint.h>
>>>
>>> void set_errno(int32_t value) {
>>> errno = value;
>>> }
>>>
>>> int32_t set_errno2(int32_t value) {
>>> errno = (int) value;
>>> return value * 2;
>>> }
>>>
>>> I compiled the code on Linux (Fedora 36) with the following command:
>>> gcc -o libCaptureCallState.so -shared -Wall libCaptureCallState.c
>>> This is the Java code causing the issue:
>>>
>>> import java.lang.foreign.FunctionDescriptor;
>>> import java.lang.foreign.Linker;
>>> import java.lang.foreign.MemoryLayout;
>>> import java.lang.foreign.MemorySegment;
>>> import java.lang.foreign.MemorySession;
>>> import java.lang.foreign.SymbolLookup;
>>> import java.lang.foreign.ValueLayout;
>>> import java.lang.invoke.MethodHandle;
>>> import java.lang.invoke.VarHandle;
>>> import java.nio.file.Path;
>>>
>>> public class TestCaptureCallState {
>>>
>>> public static void main(String[] args) throws Throwable {
>>> System.load(Path.of("libCaptureCallState.so").toAbsolutePath().toString());
>>> Linker linker = Linker.nativeLinker();
>>> SymbolLookup lookup = SymbolLookup.loaderLookup();
>>> Linker.Option.CaptureCallState state =
>>> Linker.Option.captureCallState("errno");
>>> VarHandle errno =
>>> state.layout().varHandle(MemoryLayout.PathElement.groupElement("errno"));
>>> MethodHandle setErrno = linker.downcallHandle(
>>> lookup.find("set_errno").orElseThrow(),
>>> FunctionDescriptor.ofVoid(ValueLayout.JAVA_INT),
>>> state
>>> );
>>> MethodHandle setErrno2 = linker.downcallHandle(
>>> lookup.find("set_errno2").orElseThrow(),
>>> FunctionDescriptor.of(ValueLayout.JAVA_INT,
>>> ValueLayout.JAVA_INT),
>>> state
>>> );
>>>
>>> try (MemorySession session = MemorySession.openConfined()) {
>>> MemorySegment saveSeg = session.allocate(state.layout());
>>> System.out.println("Testing set_errno ...");
>>> setErrno.invoke(saveSeg, 42);
>>> int savedErrno = (int) errno.get(saveSeg);
>>> System.out.printf("errno: %d\n", savedErrno);
>>> }
>>> try (MemorySession session = MemorySession.openConfined()) {
>>> System.out.println("Testing set_errno2 ...");
>>> MemorySegment saveSeg = session.allocate(state.layout());
>>> int result = (int) setErrno2.invoke(saveSeg, 42);
>>> int savedErrno = (int) errno.get(saveSeg);
>>> System.out.printf("errno: %d, result: %d\n", savedErrno,
>>> result);
>>> }
>>> }
>>> }
>>>
>>> I executed the code with the following commands:
>>> javac --enable-preview --release 20 TestCaptureCallState.java
>>> java --enable-preview --enable-native-access=ALL-UNNAMED
>>> TestCaptureCallState
>>> The code fails when calling the function with the return value:
>>>
>>> Testing set_errno ...
>>> errno: 42
>>> Testing set_errno2 ...
>>> #
>>> # A fatal error has been detected by the Java Runtime Environment:
>>> #
>>> # SIGSEGV (0xb) at pc=0x00007fea8ed0dce8, pid=47154, tid=47155
>>> #
>>> # JRE version: OpenJDK Runtime Environment (20.0) (build
>>> 20-internal-adhoc.maschroeder.openjdk--panama-foreign)
>>> # Java VM: OpenJDK 64-Bit Server VM
>>> (20-internal-adhoc.maschroeder.openjdk--panama-foreign, mixed mode,
>>> sharing, tiered, compressed oops, compressed class ptrs, g1 gc,
>>> linux-amd64)
>>> # Problematic frame:
>>> # V [libjvm.so+0x70dce8] DowncallLinker::capture_state(int*,
>>> int)+0x18
>>> ...
>>>
>>> Is there something that I overlooked? Is this a known limitation of
>>> the new feature?
>>>
>>> Mark
More information about the panama-dev
mailing list