Passing unaligned structs as function arguments
Manuel Bleichenbacher
manuel.bleichenbacher at gmail.com
Tue May 6 20:56:05 UTC 2025
Hi Jorn
Thanks for the answer and reference to the documentation, which I couldn't
find when I first encountered the problem.
The WINUSB_SETUP_PACKET struct isn't Windows specific. It is actually a
basic, standardized message sent to USB devices. All USB message structs
have an alignment of 1 as it cannot be controlled at what address they end
up in a receive buffer and as the USB standard tries to save every byte. It
wouldn't be strictly necessary in this case as Windows is always on the
sender side.
Regards
Manuel
Am Di., 6. Mai 2025 um 15:46 Uhr schrieb Jorn Vernee <jorn.vernee at oracle.com
>:
> 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/537c720e/attachment-0001.htm>
More information about the panama-dev
mailing list