Skip to main content

Feedback needed: improving System.loadLibrary()

8 replies [Last post]
cowwoc
Offline
Joined: 2003-08-24

System.loadLibrary() has problems loading JNI libraries that, in turn, depend upon non-JNI libraries. I've seen workarounds floating around advising developers to load the dependencies ahead of time using System.loadLibrary() but aside from being a mess to maintain these workarounds actually break under Webstart: http://bugs.sun.com/view_bug.do?bug_id=6191612

I propose the following enhancement to System.loadLibrary():

Before invoking the win32 loadLibrary() function, append java.library.path to the native search path using SetDllDirectory(): http://msdn.microsoft.com/en-us/library/ms686203(VS.85).aspx

Yes, this only works in more recent versions of Windows but it is a huge step forward in making Java behave more like native applications. Perhaps there is even a way to emulate this behavior using older APIs. I look forward to your feedback.

Thank you,
Gili

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
mlmatt
Offline
Joined: 2008-10-08

Using the PATH environment variable instead of SetDllDirectory is going to produce unexpected results in some cases. The reason for this is the order in which directories are searched for DLLs. As an example, suppose you have a JNI DLL named jni.dll and it depends on a dll named input.dll. It seems reasonable that you would put those two DLLs in the same directory and expect that when loading jni.dll it would load the input.dll that is in the same directory. Now suppose that there is another input.dll in the windows system32 directory (which there actually is on my XP machine), and that it is totally different than your input.dll. What happens under the two situations when loading jni.dll?

To quote the MSDN documentation of Visual Studio 2005:

> If SafeDllSearchMode is 1, the search order is as follows:
> 1. The directory from which the application loaded.
> 2. The system directory. Use the GetSystemDirectory function to get the path of this directory.
> 3. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
> 4. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
> 5. The current directory.
> 6. The directories that are listed in the PATH environment variable.
>
> If SafeDllSearchMode is 0, the search order is as follows:
> 1. The directory from which the application loaded.
> 2. The current directory.
> 3. The system directory. Use the GetSystemDirectory function to get the path of this directory.
> 4. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
> 5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
> 6. The directories that are listed in the PATH environment variable.

Note that in both cases the PATH environment variable is at the end. Also note that the "directory from which the application loaded" is the JRE bin directory for a java app and the browser's bin directory for an applet. So, in the case I described above, if the dll's directory is added to the PATH environment variable, then the input.dll from the system32 directory would be loaded instead of the input.dll from the jni.dll's directory. This is because the PATH directories are searched last. This is obviously not the expected behavior.

Contrast that with the SetDllDirectory search order (also from the MSDN docs for Visual Studio 2005):

> After calling SetDllDirectory, the DLL search path is:
> 1. The directory from which the application loaded.
> 2. The directory specified by the lpPathName parameter.
> 3. The system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is System32.
> 4. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is System.
> 5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
> 6. The directories that are listed in the PATH environment variable.

Now, if System.loadLibrary calls SetDllDirectory, then the directory passed in (the lpPathName parameter) is searched second, after the directory the application loaded from and before the system directories. So, in my example above, if jni.dll is loaded, it will load the input.dll in the same directory, not the input.dll from the System32 directory. This is the expected behavior, and is not achieved by modifying the PATH environment variable.

cowwoc
Offline
Joined: 2003-08-24

mlmatt,

Good catch! What do you think of calling SetDllDirectory() on those platforms that support it (XP sp1 and up) and omitting it for other platforms? Is it worth doing or are we better off as is?

Gili

mlmatt
Offline
Joined: 2008-10-08

I absolutely think it is worth doing on those platforms that support it, and as a fallback doing the PATH environment variable change you mentioned before. This would definitely be better behavior than what happens now, where it is very possible to end up loading an incorrect DLL.

As a workaround for now, I'm actually looking at building a small native class using JNI that provides an alternative to System.loadLibrary that finds the dll required, calls a native method that calls SetDllDirectory, calls System.load with the found Dll, then calls a native method that calls SetDllDirectory to reset the directory. Any reason this shouldn't work?

cowwoc
Offline
Joined: 2003-08-24

Okay guys, I filed this bug report: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6745024

This should fix System.loadLibrary() once and for all so it behaves like we expect it to. Please vote for this issue and/or push it through your contacts @ Sun :)

Thank you,
Gili

i30817
Offline
Joined: 2006-05-02

I can't vote. The register page, says the email is already registered, however when i try to get back my username (?) with it, the database says it has no corresponding username.

Let's hear it for database consistency.

cowwoc
Offline
Joined: 2003-08-24

I just found an old post I made two years ago: http://forums.java.net/jive/message.jspa?messageID=85922

We can simply use getenv(), putenv() to prefix "java.library.path" in front of the process-specific PATH. This is backwards compatible for all versions of Windows and works as expected. What do you think of this?

i30817
Offline
Joined: 2006-05-02

Everything that makes javaws work not like a complete pig should be encouraged.

Cowwoc, i think it was you that posted the workaround for that bug with addShutdownHook being interrupted during logoff or shutdown, the one where holding a reference to a JWindow would prevent that. Funnily, i never could make it work. It's annoying since i'm trying to write a very small file, and if (in my tests) i write a bigger one, (using java.exe) it works, even with the logoff scenario. I am unsure if its the ObjectOutputStream taking too long to order and serialize the object or some bug in javaws.

I wanted to get the jdk source to find out, but the requirements for windows building and for working with the corelibraries turn my hair white. No 2 and a half hours building for me, especially since i don't control the machine (can't install nothing, disk size, erases things at logoff).

Just a cry of frustration here.

cowwoc
Offline
Joined: 2003-08-24

You are absolutely right. That bug really ticks me off because it's so simple to fix, there is no reliable workaround for it and it's been a whopping 7 years since it was filed! I just posted a new discussion on that topic and I encourage you to join: http://forums.java.net/jive/thread.jspa?threadID=46716

The fix is understood. We just need them to implement it.