-
Enhancement
-
Resolution: Unresolved
-
P4
-
None
-
None
-
None
There are some cases in which clients would like to override the lifetime of a segment, so that it is equal to the lifetime of another segment (or another abstraction that has a scope - e.g. a SymbolLookup). This is currently hard to do, because the `MemorySegment::reinterpret` API wants an Arena, not a Scope.
An example of this issue is given here:
https://mail.openjdk.org/pipermail/panama-dev/2024-September/020635.html
While in this case, it would probably be enough to provide an additional linker option to override the lifetime of the pointer returned by the downcall - there are more general cases where such a solution would not be applicable.
Consider the case where a client receives a memory segment S1. The client reads a pointer from S1 and obtains a new segment S2. The client knows that the lifetime of S2 is the same as that of S1, but obviously the FFM runtime cannot know this.
The "obvious" solution would be for the client to override the lifetime of S2 to "match" that of S1. But this can only be done if the client has access to S1's Arena.
In the past, `MemorySegment::reinterpret` used to accept only a scope parameter. While this formulation is "more primitive", at some point the API was changed back to accept an Arena instead:
https://github.com/openjdk/panama-foreign/pull/812
The issue was that, in its current formulation, MemorySegment.Scope is a "pure" lifetime abstraction, and is not concerned with issues such as thread confinement. This was a rather important simplification. In the current API, an Arena has confinement (e.g. Arena::ofConfined is a confined arena), and segments also have confinement `MemorySegment::isAccessibleBy`). But MemorySegment.Scope does not deal with confinement.
As such, it becomes difficult to explain the behavior of a Scope-based reinterpret operation - such an operation cannot leave the confinement of a segment unchanged. What happens if a shared segment is given the scope of a confined arena? Now closing the confined arena could result in use-after-free issues with the reinterpreted shared segment.
A solution would be to say (as the old API did) that the reinterpreted segment carries the same confinement restriction as that of the scope - but this is problematic because (see above) Scope is a pure lifetime abstraction and doesn't really say much about confinement restrictions.
Another solution would be to simply fail to reinterpret a shared segment with a scope of a confined arena. This is probably a bit easier to specify (although still walking a fine line). Although, if we go down this path, `reinterpret(Arena)` can no longer be explained in terms of `reinterpret(Scope)` (as the former will happily turn a confined segment into shared one, and vice-versa, depending on the arena).
Finally, there is the topic of cleanup action. It is not inconceivable that a client that has only access to a Scope (and not an Arena) might want to add a cleanup action on a reinterpreted segment. This can be viewed as either:
* "morally wrong": the client doesn't have access to the Arena, and adding cleanup action requires "write" access to the Arena
* "borderline, but ok": after all, reinterpret is an restricted operation, so if a client specifies a non-sensical cleanup action, it's on them
A possible solution here would be to add extra "reinterpret" overloads which accept "Scope" (and then explain the ones accepting Arena as just calling the new overloads with Arena::scope).
An example of this issue is given here:
https://mail.openjdk.org/pipermail/panama-dev/2024-September/020635.html
While in this case, it would probably be enough to provide an additional linker option to override the lifetime of the pointer returned by the downcall - there are more general cases where such a solution would not be applicable.
Consider the case where a client receives a memory segment S1. The client reads a pointer from S1 and obtains a new segment S2. The client knows that the lifetime of S2 is the same as that of S1, but obviously the FFM runtime cannot know this.
The "obvious" solution would be for the client to override the lifetime of S2 to "match" that of S1. But this can only be done if the client has access to S1's Arena.
In the past, `MemorySegment::reinterpret` used to accept only a scope parameter. While this formulation is "more primitive", at some point the API was changed back to accept an Arena instead:
https://github.com/openjdk/panama-foreign/pull/812
The issue was that, in its current formulation, MemorySegment.Scope is a "pure" lifetime abstraction, and is not concerned with issues such as thread confinement. This was a rather important simplification. In the current API, an Arena has confinement (e.g. Arena::ofConfined is a confined arena), and segments also have confinement `MemorySegment::isAccessibleBy`). But MemorySegment.Scope does not deal with confinement.
As such, it becomes difficult to explain the behavior of a Scope-based reinterpret operation - such an operation cannot leave the confinement of a segment unchanged. What happens if a shared segment is given the scope of a confined arena? Now closing the confined arena could result in use-after-free issues with the reinterpreted shared segment.
A solution would be to say (as the old API did) that the reinterpreted segment carries the same confinement restriction as that of the scope - but this is problematic because (see above) Scope is a pure lifetime abstraction and doesn't really say much about confinement restrictions.
Another solution would be to simply fail to reinterpret a shared segment with a scope of a confined arena. This is probably a bit easier to specify (although still walking a fine line). Although, if we go down this path, `reinterpret(Arena)` can no longer be explained in terms of `reinterpret(Scope)` (as the former will happily turn a confined segment into shared one, and vice-versa, depending on the arena).
Finally, there is the topic of cleanup action. It is not inconceivable that a client that has only access to a Scope (and not an Arena) might want to add a cleanup action on a reinterpreted segment. This can be viewed as either:
* "morally wrong": the client doesn't have access to the Arena, and adding cleanup action requires "write" access to the Arena
* "borderline, but ok": after all, reinterpret is an restricted operation, so if a client specifies a non-sensical cleanup action, it's on them
A possible solution here would be to add extra "reinterpret" overloads which accept "Scope" (and then explain the ones accepting Arena as just calling the new overloads with Arena::scope).
- relates to
-
JDK-8340642 Investigate if SymbolLookup should expose the scope of the segments it returns
-
- New
-