<div dir="ltr">On Thu, Jun 5, 2025 at 1:33 AM David Holmes <<a href="mailto:david.holmes@oracle.com">david.holmes@oracle.com</a>> wrote:<br>><br>> On 5/06/2025 1:33 am, Jiangli Zhou wrote:<br>> > Ok, still thanks for the thoughts, David.<br>> ><br>> > To summarize, here is what we can do for the current step:<br>> ><br>> > - Allow JNI_OnLoad_L and etc for JDK internal native libraries with<br>> > the dynamic linking case.<br>> > - JNI spec already allows JNI_OnLoad_L and etc for dynamically linked<br>> > native libraries. No spec change is required to the above.<br>><br>> Sorry but where does the spec allow this? I thought we had agreed that<br>> this was a limitation of the implementation in regard to detecting<br>> whether a library is loaded dynamically or statically, and that we<br>> needed to document this case in the spec. ??<br><br>It's based on the following (referenced in <a href="https://mail.openjdk.org/pipermail/leyden-dev/2025-May/002144.html">https://mail.openjdk.org/pipermail/leyden-dev/2025-May/002144.html</a> message) specified in <a href="https://docs.oracle.com/en/java/javase/21/docs/specs/jni/invocation.html#support-for-statically-linked-libraries">https://docs.oracle.com/en/java/javase/21/docs/specs/jni/invocation.html#support-for-statically-linked-libraries</a>:<br><br><blockquote style="margin:0 0 0 40px;border:none;padding:0px">Support for Statically Linked Libraries</blockquote><br><blockquote style="margin:0 0 0 40px;border:none;padding:0px">"If dynamically linked library defines JNI_OnLoad_L and/or<br>JNI_OnUnload_L functions, these functions will be ignored."<br><br></blockquote>There are two parts to the above. The first part indicates that the spec allows JNI_OnLoad_L and/or JNI_OnUnload_L being defined in a dynamically linked library.<div><br></div><div>The second part stating "these functions will be ignored" however does not reflect the limitation of the implementation when handling implicitly loaded native libraries. That part needs to be documented.</div><div><br></div><div>Please let me know if that's more clear.</div><div><br></div><div>Best,</div><div><br></div><div>Jiangli<br><br>><br>> David<br>> -----<br>><br>> > - JNI_OnLoad_L and etc should not be called for dynamically linked<br>> > native libraries when the library is loaded due to loadLibrary() by<br>> > default. If a dynamic library is already loaded as a dependency of<br>> > other native libraries, when loadLibrary() is called for the library,<br>> > JNI_OnLoad_L can be called. That is an existing behavior since JDK 8.<br>> > Need to document (in spec or release notes?).<br>> ><br>> > Best,<br>> > Jiangli<br>> ><br>> > On Tue, Jun 3, 2025 at 9:31 PM David Holmes <<a href="mailto:david.holmes@oracle.com">david.holmes@oracle.com</a>> wrote:<br>> >><br>> >> On 4/06/2025 5:00 am, Jiangli Zhou wrote:<br>> >>> On Mon, Jun 2, 2025 at 6:22 PM David Holmes <<a href="mailto:david.holmes@oracle.com">david.holmes@oracle.com</a>> wrote:<br>> >>>><br>> >>>> On 3/06/2025 9:29 am, Jiangli Zhou wrote:<br>> >>>>> On Sun, Jun 1, 2025 at 7:55 PM David Holmes <<a href="mailto:david.holmes@oracle.com">david.holmes@oracle.com</a>> wrote:<br>> >>>>>><br>> >>>>>> On 31/05/2025 7:20 am, Jiangli Zhou wrote:<br>> >>>>>>> On Thu, May 29, 2025 at 11:54 PM David Holmes <<a href="mailto:david.holmes@oracle.com">david.holmes@oracle.com</a>> wrote:<br>> >>>>>>>><br>> >>>>>>>> On 30/05/2025 9:26 am, Jiangli Zhou wrote:<br>> >>>>>>>>><br>> >>>>>>>>> I just thought of one more thing related to the discussion now. Any<br>> >>>>>>>>> concern if the implementation does not ignore JNI_OnLoad_L and etc if<br>> >>>>>>>>> they are defined application's dynamically linked native libraries? Or<br>> >>>>>>>>> that's unspecified behavior and it's up to the implement to decide?<br>> >>>>>>>><br>> >>>>>>>> For Internal libraries or external? For external you have to follow the<br>> >>>>>>>> spec - if both methods exist you only want to execute one of them.<br>> >>>>>>><br>> >>>>>>> It's for the external (non-JDK) library that I'm a bit more cautious.<br>> >>>>>>><br>> >>>>>>> In the existing code in JDK mainline,<br>> >>>>>>> <a href="https://github.com/openjdk/jdk/blob/3cc630985d47be6ba4cf991698e999f17dbde203/src/java.base/share/classes/jdk/internal/loader/NativeLibraries.java#L117">https://github.com/openjdk/jdk/blob/3cc630985d47be6ba4cf991698e999f17dbde203/src/java.base/share/classes/jdk/internal/loader/NativeLibraries.java#L117</a>,<br>> >>>>>>> loadLibrary() first tries to find the built-in library using<br>> >>>>>>> JNI_OnLoad_L symbol (L is the library name). When dlsym is called to<br>> >>>>>>> find the symbol from the main process, any of the already loaded<br>> >>>>>>> shared libraries are also searched, as described by the dlsym man page<br>> >>>>>>> (included related part below).<br>> >>>>>>><br>> >>>>>>> <a href="https://man7.org/linux/man-pages/man3/dlsym.3.html">https://man7.org/linux/man-pages/man3/dlsym.3.html</a>:<br>> >>>>>>>            RTLD_DEFAULT<br>> >>>>>>>                   Find the first occurrence of the desired symbol using the<br>> >>>>>>>                   default shared object search order.  The search will<br>> >>>>>>>                   include global symbols in the executable and its<br>> >>>>>>>                   dependencies, as well as symbols in shared objects that<br>> >>>>>>>                   were dynamically loaded with the RTLD_GLOBAL flag.<br>> >>>>>>><br>> >>>>>>> I think it would be rare, it is possible to construct such case:<br>> >>>>>>><br>> >>>>>>> There are user JNI libraries A and B, with B is built as a dependency<br>> >>>>>>> of A. A defines JNI_OnLoad_A and JNI_OnLoad. B defines JNI_OnLoad_B<br>> >>>>>>> and JNI_OnLoad. When A is being loaded using loadLibrary(),<br>> >>>>>>> loadLibrary() tries first to lookup JNI_OnLoad_A, which is not found.<br>> >>>>>>> A is then loaded dynamically, which causes B being loaded implicitly<br>> >>>>>>> as a dependency of A. Later when loadLibrary() is called for B,<br>> >>>>>>> JNI_OnLoad_B would be found and then called. This is an existing<br>> >>>>>>> behavior. I think it's an unspecified behavior and we don't need to<br>> >>>>>>> add any additional checks to prevent JNI_OnLoad_B from being called.<br>> >>>>>><br>> >>>>>> That sounds like a significant design flaw to me. You can't specify that<br>> >>>>>> JNI_OnLoad_L will only be called if L is statically linked, if the<br>> >>>>>> existence of JNI_OnLoad_L is used to infer that L is statically linked!<br>> >>>>>> I would expect libraries to have both versions of the OnLoad functions<br>> >>>>>> to allow for them being statically or dynamically linked - which the<br>> >>>>>> spec allows for by saying the alternate variant is ignored. But then the<br>> >>>>>> JDK will execute the wrong method if it finds JNI_OnLoad_L in a<br>> >>>>>> dynamically linked library.<br>> >>>>><br>> >>>>> JNI_OnLoad_L is used to determine if a requested JNI native library is<br>> >>>>> a built-in (statically linked) library. Thus, it can avoid the<br>> >>>>> operation of explicit loading for the shared library, e.g. with dlopen<br>> >>>>> on Linux. JNI_OnLoad_L is expected to provide the same implementation<br>> >>>>> as JNI_OnLoad besides being used as an identifier of a built-in<br>> >>>>> library, IIUC.<br>> >>>>><br>> >>>>> In the scenario that I described in the previous message, when a JNI<br>> >>>>> shared library is already implicitly loaded as a dependency of another<br>> >>>>> native library, dlopen for explicitly loading the shared library is<br>> >>>>> not necessary. From the implementation point of view, the code seems<br>> >>>>> to have been doing the right thing since JDK 8. I did some search and<br>> >>>>> found <a href="https://stackoverflow.com/questions/32302262/does-dlopen-re-load-already-loaded-dependencies-if-so-what-are-the-implication">https://stackoverflow.com/questions/32302262/does-dlopen-re-load-already-loaded-dependencies-if-so-what-are-the-implication</a>,<br>> >>>>> which point out to the following in POSIX spec (latest<br>> >>>>> <a href="https://pubs.opengroup.org/onlinepubs/9799919799/">https://pubs.opengroup.org/onlinepubs/9799919799/</a>):<br>> >>>>><br>> >>>>> "Only a single copy of an executable object file shall be brought into<br>> >>>>> the address space, even if dlopen() is invoked multiple times in<br>> >>>>> reference to the executable object file, and even if different<br>> >>>>> pathnames are used to reference the executable object file."<br>> >>>>><br>> >>>>> Then avoiding calling dlopen for the already loaded native library<br>> >>>>> doesn't cause any undesired side effects.<br>> >>>>><br>> >>>>> Perhaps we can update the JNI spec to include the "already loaded" JNI<br>> >>>>> native libraries case, in addition to the built-in native libraries,<br>> >>>>> regarding JNI_OnLoad_L. Also clarify the "these functions will be<br>> >>>>> ignored" part in JNI spec for the dynamically linked libraries.<br>> >>>>><br>> >>>>> "If dynamically linked library defines JNI_OnLoad_L and/or<br>> >>>>> JNI_OnUnload_L functions, these functions will be ignored."<br>> >>>>><br>> >>>>> Thoughts?<br>> >>>><br>> >>>> The problem is, as I see it, that the spec assumes that if it finds the<br>> >>>> JNI_OnLoad_L symbol then L must be a statically linked library. But that<br>> >>>> ignores the case you highlight where L was implicitly dynamically loaded<br>> >>>> as a dependency on another library. Hence the existence test for the<br>> >>>> symbol is not sufficient to determine if L was statically linked.<br>> >>><br>> >>> Right.<br>> >>><br>> >>>><br>> >>>> If JNI_OnLoad_L and JNI_OnLoad were guaranteed to always do exactly the<br>> >>>> same thing it would not make any practical difference, but surely that<br>> >>>> is not always the case? I can certainly postulate the existence of a<br>> >>>> library that only needs the "on load" hook for the statically linked<br>> >>>> case, in which case invoking it when actually dynamically linked would<br>> >>>> be incorrect and potentially harmful.<br>> >>><br>> >>> Hmmm, I haven't thought of such a case. David, could you please give a<br>> >>> concrete example for the case?<br>> >><br>> >> I don't have a concrete example, that's why I just said I could<br>> >> "postulate the existence" of such a case. :)<br>> >><br>> >>>><br>> >>>> It seems we lack a way to know if a given library is truly statically<br>> >>>> linked, or to be advised when a library is implicitly loaded as a<br>> >>>> dependency. I am no expert on linking but I've been unable to locate any<br>> >>>> information on programmatically determining these conditions.<br>> >>><br>> >>> I haven't found anything either.<br>> >>><br>> >>>><br>> >>>> If there is no real solution then documenting the problem may be all we<br>> >>>> can do.<br>> >>><br>> >>> That sounds reasonable to me.<br>> >>><br>> >>> I mentioned the new mailing list discussions to Ron, Alan and Magnus<br>> >>> today during the hermetic Java meeting. They may have follow up<br>> >>> thoughts.<br>> >><br>> >> Okay.<br>> >><br>> >> David<br>> >> -----<br>> >><br>> >><br>> >>> Thanks!<br>> >>> Jiangli<br>> >>><br>> >>>><br>> >>>> David<br>> >>>> -----<br>> >>>><br>> >>>>> Thanks!<br>> >>>>> Jiangli<br>> >><br>></div></div>