-
CSR
-
Resolution: Approved
-
P3
-
None
-
behavioral
-
minimal
-
Given that negative offsets already lead to all kind of issues (e.g. passing negative offsets in the FFM API generally results in an `IllegalArgumentException`) this change shouldn't really result in loss of functionality for clients.
-
Java API
-
SE
Summary
The method MemoryLayout::byteOffsetHandle
returns a method handle that can return a negative offset.
Problem
The MemoryLayout
API defines a method, namely MemoryLayout::offsetHandle
that returns a method handle that computes the offset of the layout selected by the provided path from the start of the current layout.
The returned method handle has the following shape:
long offset_handle(long base, long index1, long index2 ... long indexN);
Where base
is a user-provided base offset, and index1
, index2
... indexN
are indices that can be used to e.g. compute offsets of array elements (there is one index per traversed sequence layout).
The returned offset can be expressed as the following sum:
offset = base + path_offset
Where path_offset
is the result of multiplying the provided indices index1
, index2
... indexN
with the corresponding array strides, and adding any additional statically known offset (e.g. the offsets of one or more accessed fields inside their defining structs).
Crucially, path_offset
can never overflow. This is guaranteed, by construction, by the MemoryLayout
API (e.g. constructing layouts whose elements have offsets that are bigger than Long.MAX_VALUE
leads to an exception), and also by the fact that index1
, index2
... indexN
are (dynamically) checked against the bounds in the corresponding sequence layouts.
But, base + path_offset
can still overflow. This can happen if the user-provided value for base
is too big. In such cases, clients can see the method handle returned by MemoryLayout::offsetHandle
return a negative value, which is incorrect and can lead to subsequent errors is such an offset is used to access a memory segment.
Solution
The solution is to make the method handle returned by MemroyLayout::offsetHandle
robust w.r.t. overflow. This can be done by making sure that base
and path_offset
are added together using e.g. Math::addExact(long, long)
.
Specification
The following API doc change is proposed:
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 989fc134a26..ea1d131a553 100644
--- a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
@@ -574,7 +574,9 @@ public sealed interface MemoryLayout
* <p>
* For any given dynamic argument {@code x_i}, it must be that {@code 0 <= x_i < size_i},
* where {@code size_i} is the size of the open path element associated with {@code x_i}.
- * Otherwise, the returned method handle throws {@link IndexOutOfBoundsException}.
+ * Otherwise, the returned method handle throws {@link IndexOutOfBoundsException}. Moreover,
+ * the value of {@code b} must be such that the computation for {@code offset} does not overflow,
+ * or the returned method handle throws {@link ArithmeticException}.
*
* @apiNote The returned method handle can be used to compute a layout offset,
* similarly to {@link #byteOffset(PathElement...)}, but more flexibly, as
- csr of
-
JDK-8338731 MemoryLayout::offsetHandle can return a negative offset
-
- Resolved
-