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