<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <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 class="moz-txt-link-freetext" href="https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/foreign/Linker.html#describing-c-sigs">https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/foreign/Linker.html#describing-c-sigs</a><br>
    </p>
    <div class="moz-cite-prefix">On 1-5-2025 20:07, Manuel
      Bleichenbacher wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:CAA7F5jLXXmtSvGavkcEc-bSGN=2-Bguaf_0OxZ1J0mx4_YbFSQ@mail.gmail.com">
      
      <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" moz-do-not-send="true" class="moz-txt-link-freetext">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" moz-do-not-send="true" class="moz-txt-link-freetext">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>
  </body>
</html>