<div dir="ltr">Hi Jorn<div><br></div><div>Thanks for the answer and reference to the documentation, which I couldn't find when I first encountered the problem.</div><div><br></div><div>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.</div><div><br></div><div>Regards</div><div>Manuel</div><div><br></div></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">Am Di., 6. Mai 2025 um 15:46 Uhr schrieb Jorn Vernee <<a href="mailto:jorn.vernee@oracle.com">jorn.vernee@oracle.com</a>>:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><u></u>
<div>
<p>Hey Manuel,</p>
<p>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:<br>
<br>
However, a native linker can still reject well-formed function
descriptors, according to platform-specific rules. For example,
some native linkers may reject <em>packed</em> struct layouts --
struct layouts whose member layouts feature relaxed alignment
constraints, to avoid the insertion of additional padding. </p>
<p>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.<br>
</p>
<p>Jorn</p>
<p>[1]:
<a href="https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/foreign/Linker.html#describing-c-sigs" target="_blank">https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/foreign/Linker.html#describing-c-sigs</a><br>
</p>
<div>On 1-5-2025 20:07, Manuel
Bleichenbacher wrote:<br>
</div>
<blockquote type="cite">
<div dir="ltr">Hi Panama team,
<div><br>
</div>
<div>This code calling a Windows API fails:</div>
<div><br>
</div>
<div><font face="monospace"> try (var arena =
Arena.ofConfined()) {<br>
var transfer =
_WINUSB_SETUP_PACKET.allocate(arena);<br>
WinUsb.WinUsb_ControlTransfer(NULL, transfer,
NULL, 0, NULL, NULL);<br>
}<br>
</font></div>
<div><br>
</div>
<div>It throws an exception:</div>
<div><br>
</div>
<div><font face="monospace"> Exception in thread "main"
java.lang.ExceptionInInitializerError<br>
at
org.example.gen.WinUsb.WinUsb_ControlTransfer(WinUsb.java:121)<br>
at org.example.App.main(App.java:53)<br>
Caused by: java.lang.IllegalArgumentException:
Unsupported layout: 1%s2<br>
at
java.base/jdk.internal.foreign.abi.AbstractLinker.checkSupported(AbstractLinker.java:293)<br>
at
java.base/jdk.internal.foreign.abi.AbstractLinker.checkLayoutRecursive(AbstractLinker.java:186)<br>
at
java.base/jdk.internal.foreign.abi.AbstractLinker.checkStructMember(AbstractLinker.java:181)<br>
at
java.base/jdk.internal.foreign.abi.AbstractLinker.checkLayoutRecursive(AbstractLinker.java:196)<br>
at
java.base/jdk.internal.foreign.abi.AbstractLinker.checkLayout(AbstractLinker.java:175)<br>
at
java.base/java.lang.Iterable.forEach(Iterable.java:75)<br>
at
java.base/jdk.internal.foreign.abi.AbstractLinker.checkLayouts(AbstractLinker.java:167)<br>
at
java.base/jdk.internal.foreign.abi.AbstractLinker.downcallHandle0(AbstractLinker.java:97)<br>
at
java.base/jdk.internal.foreign.abi.AbstractLinker.downcallHandle(AbstractLinker.java:84)<br>
at
org.example.gen.WinUsb$WinUsb_ControlTransfer.<clinit>(WinUsb.java:82)<br>
... 2 more<br>
</font></div>
<div><br>
</div>
<div>Both WinUsb_ControlTransfer() and _WINUSB_SETUP_PACKET have
been generated with jextract and are correct as far as I can
tell.</div>
<div><br>
</div>
<div>Two aspects are special in this call:</div>
<div>
<ol>
<li> _WINUSB_SETUP_PACKET is a packed struct with an
alignment of 1 byte.</li>
<li>_WINUSB_SETUP_PACKET is passed by value.</li>
</ol>
<div>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?</div>
</div>
<div><br>
</div>
<div>For reference, here is the relevant jextract generated
code:</div>
<div><br>
</div>
<div>WINUSB_SETUP_PACKET (<a href="https://learn.microsoft.com/en-us/windows/win32/api/winusb/ns-winusb-winusb_setup_packet" target="_blank">https://learn.microsoft.com/en-us/windows/win32/api/winusb/ns-winusb-winusb_setup_packet</a>):</div>
<div><br>
</div>
<div><font face="monospace"> private static final GroupLayout
$LAYOUT = MemoryLayout.structLayout(<br>
WinUsb.C_CHAR.withName("RequestType"),<br>
WinUsb.C_CHAR.withName("Request"),<br>
WinUsb.align(WinUsb.C_SHORT, 1).withName("Value"),<br>
WinUsb.align(WinUsb.C_SHORT, 1).withName("Index"),<br>
WinUsb.align(WinUsb.C_SHORT, 1).withName("Length")<br>
).withName("_WINUSB_SETUP_PACKET");<br>
</font></div>
<div><br>
</div>
<div>WinUsb_ControlTransfer (<a href="https://learn.microsoft.com/en-us/windows/win32/api/winusb/nf-winusb-winusb_controltransfer" target="_blank">https://learn.microsoft.com/en-us/windows/win32/api/winusb/nf-winusb-winusb_controltransfer</a>):</div>
<div><br>
</div>
<div><font face="monospace"> public static final
FunctionDescriptor DESC = FunctionDescriptor.of(<br>
WinUsb.C_INT,<br>
WinUsb.C_POINTER,<br>
_WINUSB_SETUP_PACKET.layout(),<br>
WinUsb.C_POINTER,<br>
WinUsb.C_LONG,<br>
WinUsb.C_POINTER,<br>
WinUsb.C_POINTER<br>
);<br>
</font></div>
<div><br>
</div>
<div>Regards,</div>
<div>Manuel</div>
<div><br>
</div>
</div>
</blockquote>
</div>
</blockquote></div>