Questions about the trivial downcall
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Thu Jul 27 13:44:38 UTC 2023
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/2dc8945e/attachment-0001.htm>
More information about the panama-dev
mailing list