Questions about the trivial downcall
Jorn Vernee
jorn.vernee at oracle.com
Thu Jul 27 14:52:53 UTC 2023
So, you would only see a crash for the JNI upcall case only when using a
debug build, but would see a crash always for the Panama upcall case.
Jorn
On 27/07/2023 16:50, Jorn Vernee wrote:
>
> We have a guarantee in UpcallLinker::on_entry to check that we are
> coming from the native thread state:
> https://github.com/openjdk/jdk/blob/8650026ff16e5c5eff897f9fd39c0c35fd8b7367/src/hotspot/share/prims/upcallLinker.cpp#L78
> (I believe we have a test for that as well).
>
> I think for JNI there's just an assert when we call from native code
> into the JNI API and transition to the VM thread state from native:
> https://github.com/openjdk/jdk/blob/8650026ff16e5c5eff897f9fd39c0c35fd8b7367/src/hotspot/share/runtime/interfaceSupport.inline.hpp#L98
>
> Jorn
>
> On 27/07/2023 15:44, Maurizio Cimadamore wrote:
>>
>> The behavior is undefined. It might crash, or not.
>>
>> While the description says that the downcall should not upcall,
>> please note that the Javadoc doesn't say anywhere that ill-behaved
>> downcalls will produce new errors. Moreover, the javadoc says this:
>>
>>> Using this linker option when linking non trivial functions is
>>> likely to have adverse effects, such as loss of performance, or JVM
>>> crashes.
>>>
>> Basically, you are in undefined behavior territory. It seems to me
>> that you are inferring too much from the javadoc.
>>
>> While I agree it might be desirable to detect this and log some kind
>> of error (see email I sent yesterday), I don't think that, as thing
>> stands, the javadoc is incorrect, and/or lacking information.
>>
>> Maurizio
>>
>>
>> On 27/07/2023 14:40, Cheng Jin wrote:
>>>
>>> But I tried a simple example to indirectly trigger a JNI upcall
>>> within a trivial FFM downcall by saving a global JNIEnv within a JNI
>>> downcall at first which works good as follows. Does it mean that a
>>> FFM trivial downcall literally doesn’t stop a JNI upcall which seems
>>> inconsistent with the description of
>>> https://download.java.net/java/early_access/jdk21/docs/api/java.base/java/lang/foreign/Linker.Option.html#isTrivial()
>>> <https://urldefense.com/v3/__https://download.java.net/java/early_access/jdk21/docs/api/java.base/java/lang/foreign/Linker.Option.html*isTrivial()__;Iw!!ACWV5N9M2RV99hQ!KpMq9yrQInVdYsiAcZWCDTeOZd_GLJwrDN4n06JvbKQ194M_eabqlUaxzgDuSjbnoxQLukS4Uu8wT7q__xolFW5e$>
>>>
>>> or OpenJDK doesn’t support such behavior mixed with JNI & FFM?
>>>
>>> *[1] JniTest.java*
>>>
>>> public class JniTest {
>>>
>>> private static Linker linker = Linker.nativeLinker();
>>>
>>> static {
>>>
>>> System.loadLibrary("jnitest");
>>>
>>> }
>>>
>>> private static final SymbolLookup nativeLibLookup =
>>> SymbolLookup.loaderLookup();
>>>
>>> private native int addJNI2Ints(int arg1, int arg2);
>>>
>>> public int *addJNI2Ints_Upcall*(int arg1, int arg2) {
>>>
>>> int sum = arg1 + arg2;
>>>
>>> System.out.println("trivial: addJNI2Ints_Upcall: sum = " + sum);
>>>
>>> return sum;
>>>
>>> }
>>>
>>> public void test_add2Ints() throws Throwable {
>>>
>>> FunctionDescriptor fd = FunctionDescriptor.of(JAVA_INT, JAVA_INT,
>>> JAVA_INT);
>>>
>>> MemorySegment functionSymbol = nativeLibLookup.find("add2Ints").get();
>>>
>>> MethodHandle mh = linker.downcallHandle(functionSymbol, fd,
>>> *Linker.Option.isTrivial()*);
>>>
>>> int result = (int)mh.invokeExact(112, 123);
>>>
>>> System.out.println("test_add2Ints result = " + result);
>>>
>>> }
>>>
>>> public static void main(String[] args) throws Throwable {
>>>
>>> JniTest test = new JniTest();
>>>
>>> int sum = test.*addJNI2Ints*(112, 123); ß-- call the JNI native at
>>> first to save the global JNIEnv & jobject
>>>
>>> System.out.println("addJNI2Ints sum = " + sum);
>>>
>>> test.test_*add2Ints*(); ß-- use saved the global JNIEnv & jobject to
>>> trigger a JNI upcall in native.
>>>
>>> }
>>>
>>> }
>>>
>>> *[2] JniTest.c*
>>>
>>> #include <jni.h>
>>>
>>> #include "JniTest.h"
>>>
>>> JNIEnv *globalEnv;
>>>
>>> jobject globalObj;
>>>
>>> JNIEXPORT int JNICALL Java_JniTest_addJNI2Ints(JNIEnv *env, jobject
>>> thisObj, jint arg1, jint arg2) {
>>>
>>> jint intSum = arg1 + arg2;
>>>
>>> globalEnv = env;
>>>
>>> globalObj = thisObj;
>>>
>>> printf("\nJava_JniTest_addJNI2Ints: env = %p, globalObj = %p\n",
>>> globalEnv, globalObj);
>>>
>>> return intSum;
>>>
>>> }
>>>
>>> int
>>>
>>> add2Ints(int intArg1, int intArg2)
>>>
>>> {
>>>
>>> printf("\nadd2Ints: globalEnv = %p, globalObj = %p\n", globalEnv,
>>> globalObj);
>>>
>>> jclass clazz = (*globalEnv)->GetObjectClass(globalEnv, globalObj);
>>>
>>> jmethodID method = (*globalEnv)->GetMethodID(globalEnv, clazz,
>>> "addJNI2Ints_Upcall", "(II)I");
>>>
>>> return (*globalEnv)->CallIntMethod(globalEnv, globalObj, method,
>>> intArg1, intArg2);
>>>
>>> }
>>>
>>> [3]Commands:
>>>
>>> ./jdk21_hotspot_x86_64/bin/javac --enable-preview --source 21 -h .
>>> JniTest.java
>>>
>>> gcc -fPIC -I"./jdk21_hotspot_x86_64/include"
>>> -I"./jdk21_hotspot_x86_64/include/linux" -shared -g -o
>>> libjnitest.so JniTest.c
>>>
>>> ./jdk21_hotspot_x86_64/bin/java --enable-preview
>>> -Djava.library.path=./jnitests --enable-native-access=ALL-UNNAMED
>>> -Dforeign.restricted=permit JniTest
>>>
>>> [4] Output:
>>>
>>> Java_JniTest_addJNI2Ints: env = 0x7f81f8028a08, globalObj =
>>> 0x7f81ff379998
>>>
>>> addJNI2Ints sum = 235
>>>
>>> add2Ints: intSum = 235
>>>
>>> add2Ints: globalEnv = 0x7f81f8028a08, globalObj = 0x7f81ff379998
>>>
>>> *trivial: addJNI2Ints_Upcall: sum = 235 **ß***
>>>
>>> test_add2Ints result = 235
>>>
>>> Best Regards
>>>
>>> Cheng Jin
>>>
>>> *From:*Maurizio Cimadamore <maurizio.cimadamore at oracle.com>
>>> *Sent:* Wednesday, July 26, 2023 8:45 PM
>>> *To:* Cheng Jin <jincheng at ca.ibm.com>; panama-dev at openjdk.org
>>> *Subject:* [EXTERNAL] Re: Questions about the trivial downcall
>>>
>>> On 27/07/2023 01: 40, Cheng Jin wrote: >> Right, JNI has not much to
>>> do with this. There's different ways to upcall back into Java (JNI
>>> and FFM upcall stubs). If so, my understanding is that both JNI and
>>> FFM upcall should crash the VM
>>>
>>> ZjQcmQRYFpfptBannerStart
>>>
>>> *This Message Is From an External Sender *
>>>
>>> This message came from outside your organization.
>>>
>>> * Report Suspicious *
>>> <https://us-phishalarm-ewt.proofpoint.com/EWT/v1/PjiDSg!2c-hYpT1IJMQ-iYRkuvEjWPesZVtAje5jWUBYoL2pAM1wRGP31iKedgOBvqFHgP6rIVsAh-wdcVItzgnQJ8qkuKPFDFOpo-3zg$>
>>>
>>>
>>> ZjQcmQRYFpfptBannerEnd
>>>
>>> On 27/07/2023 01:40, Cheng Jin wrote:
>>>
>>> >> Right, JNI has not much to do with this. There's different
>>> ways to upcall back into Java (JNI and FFM upcall stubs).
>>>
>>> If so, my understanding is that both JNI and FFM upcall should
>>> crash the VM in a trivial FFM downcall, correct?
>>>
>>> I believe so. Jorn will confirm.
>>>
>>> Maurizio
>>>
>>> Best Regards
>>>
>>> Cheng Jin
>>>
>>> *From:*Maurizio Cimadamore <maurizio.cimadamore at oracle.com>
>>> <mailto:maurizio.cimadamore at oracle.com>
>>> *Sent:* Wednesday, July 26, 2023 8:29 PM
>>> *To:* Cheng Jin <jincheng at ca.ibm.com>
>>> <mailto:jincheng at ca.ibm.com>; panama-dev at openjdk.org
>>> <mailto:panama-dev at openjdk.org>
>>> *Subject:* [EXTERNAL] Re: Questions about the trivial downcall
>>>
>>> and does not call back into Java (e. g. using an upcall stub).
>>> ß------------------------- it occurs to me that any kind of
>>> upcall should be disallowed in such case whether it is JNI or
>>> FFM, am I correct? Right, JNI has not much to do with this.
>>>
>>> ZjQcmQRYFpfptBannerStart
>>>
>>> *This Message Is From an External Sender *
>>>
>>> This message came from outside your organization.
>>>
>>> * Report Suspicious *
>>> <https://us-phishalarm-ewt.proofpoint.com/EWT/v1/PjiDSg!2c-gyJS_6lP6sKYb2IHEjb2TaeBqM7xJQ9RStijLaImfla_LrFEK8T2PB5_umxDwUuL8X7BGAHosOeXRLCglJfzdYnJaiHF6gQ$>
>>>
>>>
>>> ZjQcmQRYFpfptBannerEnd
>>>
>>> and does not call back into Java (e.g. using an upcall
>>> stub). ß------------------------- it occurs to me that any
>>> kind of upcall should be disallowed in such case whether it
>>> is JNI or FFM, am I correct?
>>>
>>> Right, JNI has not much to do with this. There's different ways
>>> to upcall back into Java (JNI and FFM upcall stubs).
>>>
>>> Your question is: what happens if we do call back when we are in
>>> trivial mode.
>>>
>>> I believe the answer is "we crash" (but not in a "nice way"),
>>> and I'm not too sure we can do much to prevent that. I believe
>>> Jorn knows more on that topic.
>>>
>>> Maurizio
>>>
>>> Best Regards
>>>
>>> Cheng Jin
>>>
>>> *From:*Maurizio Cimadamore <maurizio.cimadamore at oracle.com>
>>> <mailto:maurizio.cimadamore at oracle.com>
>>> *Sent:* Wednesday, July 26, 2023 7:44 PM
>>> *To:* Cheng Jin <jincheng at ca.ibm.com>
>>> <mailto:jincheng at ca.ibm.com>; panama-dev at openjdk.org
>>> <mailto:panama-dev at openjdk.org>
>>> *Subject:* [EXTERNAL] Re: Questions about the trivial downcall
>>>
>>> Hi, a trivial downcall is supposed to target a native
>>> function that (a) terminates quickly (so as not to block the
>>> GC for too long) and (b) does not upcall into Java. So, no,
>>> a trivial downcall cannot trigger upcalls (I don't think we
>>> detect
>>>
>>> ZjQcmQRYFpfptBannerStart
>>>
>>> *This Message Is From an External Sender *
>>>
>>> This message came from outside your organization.
>>>
>>> * Report Suspicious *
>>> <https://us-phishalarm-ewt.proofpoint.com/EWT/v1/PjiDSg!2c-r455VanMQ2qYReaGl7Z4QRx46ATMxAjK9nbXsj13QlLeimn0PtcIAb-U80cJ-A34Q8dYfoQ6JN5nMYOpBz-Hn3cuAGTZLJQ$>
>>>
>>>
>>> ZjQcmQRYFpfptBannerEnd
>>>
>>> Hi,
>>> a trivial downcall is supposed to target a native function
>>> that (a) terminates quickly (so as not to block the GC for
>>> too long) and (b) does not upcall into Java.
>>>
>>> So, no, a trivial downcall cannot trigger upcalls (I don't
>>> think we detect this, I believe the JVM just crashes if you do).
>>>
>>> Also I notice that you speak of "JNI" upcall. Is that what
>>> you really mean - e.g. a trivial FFM downcall making an
>>> upcall using JNI? In general, I think it's a bit hard for
>>> downcalls to do anything that has to do with JNI because the
>>> invoked native function is not passed a JNIEnv - FFM really
>>> just bridges the Java code with the native library function
>>> you want to call, nothing more. (I suppose that function
>>> could get its hands on the VM using the JNI attach API, but
>>> I feel that's a different question from what you were asking?).
>>>
>>> Maurizio
>>>
>>> On 26/07/2023 22:23, Cheng Jin wrote:
>>>
>>> Hi there,
>>>
>>> I’ve got a couple of questions about the behavior of a
>>> trivial downcall (with *isTrivial* specified).
>>>
>>> Is a FFI downcall able to trigger a JNI upcall ?
>>>
>>> If so, should a JNI upcall should be captured in this
>>> trivial downcall?
>>>
>>> Best Regards
>>>
>>> Cheng Jin
>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/panama-dev/attachments/20230727/d7f6bbb0/attachment-0001.htm>
More information about the panama-dev
mailing list