Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8310068

VarHandle and slice handle derived from layout are lacking alignment check

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P3 P3
    • 21, 22
    • core-libs
    • None
    • behavioral
    • minimal
    • Hide
      Misaligned accesses are generally indicative of a bug in the program, where an address has become corrupt. In some cases a valid use case might produce an exception, in which case a user would have to adjust the alignment constraint of the layout involved.
      Show
      Misaligned accesses are generally indicative of a bug in the program, where an address has become corrupt. In some cases a valid use case might produce an exception, in which case a user would have to adjust the alignment constraint of the layout involved.
    • Java API
    • SE

      Summary

      VarHandles and MethodHandles derived from MemoryLayout through MemoryLayout::varHandle and MemoryLayout::sliceHandle should check the alignment of the accessed address using the alignment constraint of the root layout, rather than just the accessed layout.

      Problem

      Through the methods MemoryLayout::varHandle and MemoryLayout::sliceHandle, a nested element of a memory layout can be accessed. For instance a field of a struct. The needed offset computations are captured in the VarHandle or MethodHandle.

      Upon an access using one of these handles, the (base address + offset) is checked to see if it is aligned according to alignment constraint of the accessed element.

      However, this does not guarantee that the base address is aligned, as the alignment constraint of the root layout might be stricter than the constraint of the accessed element.

      For instance, a struct with 2 layouts JAVA_INT and JAVA_SHORT, has an alignment constraint of 4 bytes, while the second element, the JAVA_SHORT only has an alignment constraint of 2 bytes. When doing an access, the accessed address (base address + offset) might be 2 byte aligned, but the base address might not be 4 byte aligned.

      This is an issue, as essentially we are allowing a partially unaligned access, which would not be normally possible when using the simple getters/setter and asSlice methods on MemorySegment.

      Solution

      Change the bahvior of the returned handles to check the alignment of the base address as well.

      Specification

      There is already a general overview of alignment checking in the class javadoc of MemorySegment. But, for emphasis, a note is added to the doc of the relevant methods as well:

      diff --git a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
      index 10f57aa436a5..60f493b308bf 100644
      --- a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
      +++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
      @@ -380,6 +380,10 @@ default MethodHandle byteOffsetHandle(PathElement... elements) {
            * Additionally, the provided dynamic values must conform to bounds which are derived from the layout path, that is,
            * {@code 0 <= x_i < b_i}, where {@code 1 <= i <= n}, or {@link IndexOutOfBoundsException} is thrown.
            * <p>
      +     * The base address must be <a href="MemorySegment.html#segment-alignment">aligned</a> according to the {@linkplain
      +     * #byteAlignment() alignment constraint} of the root layout (this layout). Note that this can be more strict
      +     * (but not less) than the alignment constraint of the selected value layout.
      +     * <p>
            * Multiple paths can be chained, with <a href=#deref-path-elements>dereference path elements</a>.
            * A dereference path element constructs a fresh native memory segment whose base address is the address value
            * read obtained by accessing a memory segment at the offset determined by the layout path elements immediately preceding
      @@ -436,6 +440,10 @@ default VarHandle varHandle(PathElement... elements) {
            * long size = select(elements).byteSize();
            * MemorySegment slice = segment.asSlice(offset, size);
            * }
      +     * <p>
      +     * The segment to be sliced must be <a href="MemorySegment.html#segment-alignment">aligned</a> according to the
      +     * {@linkplain #byteAlignment() alignment constraint} of the root layout (this layout). Note that this can be more
      +     * strict (but not less) than the alignment constraint of the selected value layout.
            *
            * @apiNote The returned method handle can be used to obtain a memory segment slice, similarly to {@link MemorySegment#asSlice(long, long)},
            * but more flexibly, as some indices can be specified when invoking the method handle.

            jvernee Jorn Vernee
            jvernee Jorn Vernee
            Maurizio Cimadamore
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: