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

j.l.foreign.VaList::nextVarg call could throw IndexOutOfBoundsException or even crash the VM

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P3 P3
    • 19
    • core-libs
    • None
    • behavioral
    • minimal
    • Out-of-bounds reads were already an invalid use case, we now just throw and exception. The existing API is also an incubator API (moved to preview in 19).
    • Java API

      Summary

      Change the VaList::nextVarg methods to try and detect out-of-bounds reads, and throw NoSuchElementException in such cases.

      Problem

      Reads from VaLists created in Java, using the VaList::make method, should be safe. However, in practice out-of-bounds reads can occur, which have the potential to crash the VM on some platforms.

      Solution

      Detect out-of-bounds reads for VaLists created from Java using VaList::make, and throw NoSuchElementException in those cases.

      Specification

      The javadoc of VaList has the following diff:

      @@ -50,7 +51,16 @@
        * <p>
        * As such, this interface only supports reading {@code int}, {@code double},
        * and any other type that fits into a {@code long}.
      - *
      + * <h2 id="safety">Safety considerations</h2>
      + * It is possible for clients to access elements outside the spatial bounds of a variable argument list.
      + * Variable argument list implementations will try to detect out-of-bounds reads on a best-effort basis.
      + * <p>
      + * Whether this detection succeeds depends on the factory method used to create the variable argument list:
      + * <ul>
      + *     <li>Variable argument lists created <em>safely</em>, using {@link #make(Consumer, MemorySession)} are capable of detecting out-of-bounds reads;</li>
      + *     <li>Variable argument lists created <em>unsafely</em>, using {@link #ofAddress(MemoryAddress, MemorySession)} are not capable of detecting out-of-bounds reads</li>
      + * </ul>
      + * <p>
        * This class is not thread safe, and all accesses should occur within a single thread
        * (regardless of the memory session associated with the variable arity list).
        *
      @@ -74,6 +84,7 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
            * {@linkplain MemorySession#isAlive() alive}.
            * @throws WrongThreadException if this method is called from a thread other than the thread owning
            * the {@linkplain #session() session} associated with this variable argument list.
      +     * @throws NoSuchElementException if an <a href=VaList.html#safety>out-of-bounds</a> read is detected.
            */
           int nextVarg(ValueLayout.OfInt layout);
      
      @@ -87,6 +98,7 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
            * {@linkplain MemorySession#isAlive() alive}.
            * @throws WrongThreadException if this method is called from a thread other than the thread owning
            * the {@linkplain #session() session} associated with this variable argument list.
      +     * @throws NoSuchElementException if an <a href=VaList.html#safety>out-of-bounds</a> read is detected.
            */
           long nextVarg(ValueLayout.OfLong layout);
      
      @@ -100,6 +112,7 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
            * {@linkplain MemorySession#isAlive() alive}.
            * @throws WrongThreadException if this method is called from a thread other than the thread owning
            * the {@linkplain #session() session} associated with this variable argument list.
      +     * @throws NoSuchElementException if an <a href=VaList.html#safety>out-of-bounds</a> read is detected.
            */
           double nextVarg(ValueLayout.OfDouble layout);
      
      @@ -113,6 +126,7 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
            * {@linkplain MemorySession#isAlive() alive}.
            * @throws WrongThreadException if this method is called from a thread other than the thread owning
            * the {@linkplain #session() session} associated with this variable argument list.
      +     * @throws NoSuchElementException if an <a href=VaList.html#safety>out-of-bounds</a> read is detected.
            */
           MemoryAddress nextVarg(ValueLayout.OfAddress layout);
      
      @@ -135,6 +149,7 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
            * {@linkplain MemorySession#isAlive() alive}.
            * @throws WrongThreadException if this method is called from a thread other than the thread owning
            * the {@linkplain #session() session} associated with this variable argument list.
      +     * @throws NoSuchElementException if an <a href=VaList.html#safety>out-of-bounds</a> read is detected.
            */
           MemorySegment nextVarg(GroupLayout layout, SegmentAllocator allocator);
      
      @@ -146,6 +161,7 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
            * {@linkplain MemorySession#isAlive() alive}.
            * @throws WrongThreadException if this method is called from a thread other than the thread owning
            * the {@linkplain #session() session} associated with this variable argument list.
      +     * @throws NoSuchElementException if an <a href=VaList.html#safety>out-of-bounds</a> read is detected.
            */
           void skip(MemoryLayout... layouts);
      
      @@ -185,6 +201,8 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
            * the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
            * restricted methods, and use safe and supported functionalities, where possible.
            *
      +     * @implNote variable argument lists created using this method can not detect <a href=VaList.html#safety>out-of-bounds</a> reads.
      +     *
            * @param address a memory address pointing to an existing variable argument list.
            * @param session the memory session to be associated with the returned variable argument list.
            * @return a new variable argument list backed by the memory region at {@code address}.
      @@ -214,6 +232,8 @@ static VaList ofAddress(MemoryAddress address, MemorySession session) {
            * Note that when there are no elements added to the created va list,
            * this method will return the same as {@link #empty()}.
            *
      +     * @implNote variable argument lists created using this method can detect <a href=VaList.html#safety>out-of-bounds</a> reads.
      +     *
            * @param actions a consumer for a builder (see {@link Builder}) which can be used to specify the elements
            *                of the underlying variable argument list.
            * @param session the memory session to be associated with the new variable arity list.

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

              Created:
              Updated:
              Resolved: