Passing unaligned structs as function arguments
Jorn Vernee
jorn.vernee at oracle.com
Tue May 6 13:37:51 UTC 2025
Hey Manuel,
The current linker implementations do indeed not support packed structs.
Packed structs, as well as structs with bit fields, are not specified
very well by most ABIs, so the decision was made to conservatively
reject them on all platforms. Most libraries avoid using by-value packed
structs for this reason as well. This is covered by the documentation at
the end of the 'Describing C signatures' section [1], where it states:
However, a native linker can still reject well-formed function
descriptors, according to platform-specific rules. For example, some
native linkers may reject /packed/ struct layouts -- struct layouts
whose member layouts feature relaxed alignment constraints, to avoid the
insertion of additional padding.
In this case, the alignment of the fields does not have any impact on
the layout of the struct (there is no padding either way). So, dropping
the alignment, like you did, should result on the function being
callable. I suspect the alignment is set to 1 for these fields to allow
the struct to be placed at an address that is 1-byte-aligned.
Jorn
[1]:
https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/foreign/Linker.html#describing-c-sigs
On 1-5-2025 20:07, Manuel Bleichenbacher wrote:
> Hi Panama team,
>
> This code calling a Windows API fails:
>
> try (var arena = Arena.ofConfined()) {
> var transfer = _WINUSB_SETUP_PACKET.allocate(arena);
> WinUsb.WinUsb_ControlTransfer(NULL, transfer, NULL, 0,
> NULL, NULL);
> }
>
> It throws an exception:
>
> Exception in thread "main" java.lang.ExceptionInInitializerError
> at org.example.gen.WinUsb.WinUsb_ControlTransfer(WinUsb.java:121)
> at org.example.App.main(App.java:53)
> Caused by: java.lang.IllegalArgumentException: Unsupported layout:
> 1%s2
> at
> java.base/jdk.internal.foreign.abi.AbstractLinker.checkSupported(AbstractLinker.java:293)
> at
> java.base/jdk.internal.foreign.abi.AbstractLinker.checkLayoutRecursive(AbstractLinker.java:186)
> at
> java.base/jdk.internal.foreign.abi.AbstractLinker.checkStructMember(AbstractLinker.java:181)
> at
> java.base/jdk.internal.foreign.abi.AbstractLinker.checkLayoutRecursive(AbstractLinker.java:196)
> at
> java.base/jdk.internal.foreign.abi.AbstractLinker.checkLayout(AbstractLinker.java:175)
> at java.base/java.lang.Iterable.forEach(Iterable.java:75)
> at
> java.base/jdk.internal.foreign.abi.AbstractLinker.checkLayouts(AbstractLinker.java:167)
> at
> java.base/jdk.internal.foreign.abi.AbstractLinker.downcallHandle0(AbstractLinker.java:97)
> at
> java.base/jdk.internal.foreign.abi.AbstractLinker.downcallHandle(AbstractLinker.java:84)
> at
> org.example.gen.WinUsb$WinUsb_ControlTransfer.<clinit>(WinUsb.java:82)
> ... 2 more
>
> Both WinUsb_ControlTransfer() and _WINUSB_SETUP_PACKET have been
> generated with jextract and are correct as far as I can tell.
>
> Two aspects are special in this call:
>
> 1. _WINUSB_SETUP_PACKET is a packed struct with an alignment of 1 byte.
> 2. _WINUSB_SETUP_PACKET is passed by value.
>
> Is it a restriction of FFM that unaligned structs cannot be passed by
> value (it works if the natural alignment of 2 bytes is used)? Or what
> is the issue here?
>
> For reference, here is the relevant jextract generated code:
>
> WINUSB_SETUP_PACKET
> (https://learn.microsoft.com/en-us/windows/win32/api/winusb/ns-winusb-winusb_setup_packet):
>
> private static final GroupLayout $LAYOUT = MemoryLayout.structLayout(
> WinUsb.C_CHAR.withName("RequestType"),
> WinUsb.C_CHAR.withName("Request"),
> WinUsb.align(WinUsb.C_SHORT, 1).withName("Value"),
> WinUsb.align(WinUsb.C_SHORT, 1).withName("Index"),
> WinUsb.align(WinUsb.C_SHORT, 1).withName("Length")
> ).withName("_WINUSB_SETUP_PACKET");
>
> WinUsb_ControlTransfer
> (https://learn.microsoft.com/en-us/windows/win32/api/winusb/nf-winusb-winusb_controltransfer):
>
> public static final FunctionDescriptor DESC = FunctionDescriptor.of(
> WinUsb.C_INT,
> WinUsb.C_POINTER,
> _WINUSB_SETUP_PACKET.layout(),
> WinUsb.C_POINTER,
> WinUsb.C_LONG,
> WinUsb.C_POINTER,
> WinUsb.C_POINTER
> );
>
> Regards,
> Manuel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/panama-dev/attachments/20250506/fbe3889d/attachment.htm>
More information about the panama-dev
mailing list