Questions about the trivial downcall

Jorn Vernee jorn.vernee at oracle.com
Thu Jul 27 14:50:35 UTC 2023


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/c83c441c/attachment-0001.htm>


More information about the panama-dev mailing list