Skip to content

Conversation

AditiS11
Copy link

@AditiS11 AditiS11 commented Sep 24, 2025

Fixes: #22573
Ensure that checkValidState() is called for confined
memory segments which are passed as arguments to
the native call when argValue.address is invoked.
Make memArgScopeSet thread local.

With the following change, this is the error produced for the issue:

main result = 150 java.lang.WrongThreadException: Attempted access outside owning thread	at java.base/jdk.internal.foreign.MemorySessionImpl.wrongThread(MemorySessionImpl.java:330)	at java.base/jdk.internal.misc.ScopedMemoryAccess$ScopedAccessError.newRuntimeException(ScopedMemoryAccess.java:114)	at java.base/jdk.internal.foreign.MemorySessionImpl.checkValidState(MemorySessionImpl.java:217)	at java.base/openj9.internal.foreign.abi.InternalDowncallHandler.memSegmtOfPtrToLongArg(InternalDowncallHandler.java:295)	at ConfinedMemorySegmentDowncallTest.makeDownCall(ConfinedMemorySegmentDowncallTest.java:26)	at ConfinedMemorySegmentDowncallTest.lambda$main$0(ConfinedMemorySegmentDowncallTest.java:44)	at java.base/java.lang.Thread.run(Thread.java:1485) 
@AditiS11 AditiS11 force-pushed the Issue-22573 branch 2 times, most recently from 79a4f0d to 7f35e22 Compare September 24, 2025 17:30
@pshipton pshipton requested a review from tajila September 24, 2025 18:05
try {
return (long) originalFilter.invokeExact(seg);
} finally {
sessionImpl.release0();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wont work as you are releasing ownership of the memory segment before the call is made.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the way to solve this is to add a new field to HeapArgInfo called something like MemorySessionImpl[] sessions.

In the memSegmtToLongArg you can acquire the session and also add it to the active info.sessions[]. In runNativeMethod after the native has been called and before info.clear() is called, you can iterate thorugh all the sessions and release them.

Copy link
Author

@AditiS11 AditiS11 Sep 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @tajila . I hadn't removed the acquire0 call in SetDependency, I guess thats why the tests passed.
As there is already a call to acquire0 in SetDependency(), can we just call CheckValidState() here to ensure the confined MemorySegment is only accessed by the owner thread?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @tajila . I hadn't removed the acquire0 call in SetDependency, I guess thats why the tests passed. As there is already a call to acquire0 in SetDependency(), can we just call CheckValidState() here to ensure the confined MemorySegment is only accessed by the owner thread?

I think this could just be a call to CheckValidState or similar since the fields are already being acquired in SetDependency.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya good point. I think SetDependency already does the required access/release checks. The one issue with the way its currently done is that memArgScopeSet is not thread local. Perhaps this is the only thing that needs to be changed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The session for the native call and the session for the args arent guaranteed to be the same.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

acquire0 for GlobalSession (the scope that can't be closed) does not do anything.

There is also ImplicitSession which doesnt explicitly close.

Copy link
Contributor

@tajila tajila Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

acquire0 for GlobalSession (the scope that can't be closed) does not do anything.

My concern is that session(the native call session) can be global, but memArgSession can be confined. Currently the if ((owner == Thread.currentThread()) || (owner == null)) { check is against the memArgSession, but then the closeable action is on the native call session. Unless I've missed something it seems like its possible a confined session on an arg would never be closed unless the arg sessions are explcitly closed after the call.

Copy link
Author

@AditiS11 AditiS11 Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In runNativeMethod, I see that the downcall is always wrapped in a confined Arena (https://github.com/eclipse-openj9/openj9/blob/master/jcl/src/java.base/share/classes/openj9/internal/foreign/abi/InternalDowncallHandler.java#L932) so I think the native call session is never global. Are there other contexts where the native call session could be global or implicit?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, then my previous concern is not valid. But memArgSession still needs to be thread local.

@AditiS11 AditiS11 marked this pull request as draft September 25, 2025 09:51
@AditiS11 AditiS11 force-pushed the Issue-22573 branch 2 times, most recently from efc1e05 to 982049a Compare September 26, 2025 11:13
@AditiS11 AditiS11 marked this pull request as ready for review September 26, 2025 11:15
@AditiS11 AditiS11 requested a review from tajila September 27, 2025 01:01
private long[] offsets;
private int index;
private final int size;
private MemorySessionImpl[] sessions;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just realized, this can actually be an array list List<MemorySessionImpl> because we dont actually care about the position.We just need to keep track of all of them.

}

void addSession(MemorySessionImpl session) {
sessions[index - 1] = session;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can just add to the array list.

@tajila
Copy link
Contributor

tajila commented Sep 30, 2025

jenkins test sanity alinux64 jdk25

@AditiS11 AditiS11 force-pushed the Issue-22573 branch 3 times, most recently from 864edbf to a3796ec Compare September 30, 2025 14:06
@tajila
Copy link
Contributor

tajila commented Sep 30, 2025

jenkins test sanity alinux64 jdk25

@keithc-ca
Copy link
Contributor

@TobiAjila PR builds may be a little premature; the code as is will not compile for Java 21. See #22675 (comment).

*/
/*[IF JAVA_SPEC_VERSION >= 21]*/
private Set<Scope> memArgScopeSet;
private final ThreadLocal<Set<Scope>> memArgScopeSet = ThreadLocal.withInitial(HashSet::new);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll have the same problem here as last time with recursive calls. This should be added to HeapArgInfo.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, HeapArgInfo is used only for Java versions 22 and above, while memArgScopeSet exists for Java versions 21 and above. If we move memArgScopeSet inside HeapArgInfo, could this cause issues? (Tried the change for Java 25 and it worked)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can include HeapArgInfo in jdk21 but exlude all the fields that arent used and just keep memArgScopeSet

@AditiS11 AditiS11 marked this pull request as draft October 6, 2025 17:06
@AditiS11 AditiS11 marked this pull request as ready for review October 7, 2025 16:28
@AditiS11 AditiS11 marked this pull request as draft October 8, 2025 17:46
@AditiS11 AditiS11 force-pushed the Issue-22573 branch 2 times, most recently from 26465e4 to a346b4c Compare October 9, 2025 12:17
@AditiS11 AditiS11 marked this pull request as ready for review October 9, 2025 12:29
Fixes: eclipse-openj9#22573 Ensure that checkValidState is called for memory segments which are passed as arguments to the native call when argValue.address is invoked. Make memArgScopeSet thread local.
@keithc-ca
Copy link
Contributor

Please add a test to validate change.

@AditiS11
Copy link
Author

Please add a test to validate change.

Tested the change with the test case mentioned in the issue. It throws the required WrongThreadException now.
Please let me know if there is anything else that needs to be checked.

@keithc-ca
Copy link
Contributor

A manual test is fine, but we should have test code in this repository that automatically checks that the issue does not return.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

4 participants