Bug: Impossible to load 2+ independent applications if both are using the same JFX version (Windows, JFX 23.0.2+3)
Cormac Redmond
credmond at certak.com
Thu Feb 6 19:56:57 UTC 2025
Hi,
I have found a "serious" bug, where two completely independent JFX
applications, both with their own embedded runtime (built with jlink &
jpackage) & using the same JavaFX version, are unable to run
simultaneously, because of the JFX cache -- at least on Windows.
When trying to run any application, NativeLibLoader does a checksum on DLLs
in the cache (e.g.: C:\Users\xyz\.openjfx\cache\23.0.2+3\amd64\prism_d3d.dll);
and tries to delete any files that exist where the checksums do not match
(in order to replace them):
if (!Arrays.equals(isHash, fileHash)) {
> Files.delete(f.toPath());
> }
But a second application *fails* to start, as it is unable to delete these
files because they're in use by the first application (see stacktrace
below).
But why are the checksums different, shouldn't they be the same? They are
different because the DLLs are signed by the builder of the applications --
different authors and different timestamps. So the DLL checksums will be
different despite the DLLs being the same, in terms of the JFX version.
Why are these JFX DLLs signed by the authors? Because for some reason, they
come *unsigned*, and all DLLs when packaged *should* be signed, including
any embedded in JARs, to avoid alarming Windows Defender warnings and
mistrust, etc. There's no point spending a small fortune on Windows
code-signing certs and shipping with any unsigned third-party DLLs
(including any embedded in JARs). You might sign your own binaries and any
unsigned third-party binaries. Similarly for MacOS, everything, including
embedded native libs in JARs, etc., needs to be signed for gatekeeper &
notarization to allow it.
So it would be better if JFX DLLs came signed, to avoid forcing developers
to do it (which would also avoid this checksum mishap). Or, if developers
need to sign Oracle's DLLs, then this checksum approach isn't suitable.
Also, there should really be a proper fallback in place -- a cache bug
should not have such a catastrophic outcome.
FYI: JLink also removes signatures from a bunch of JDK DLLs when assembling
the runtime, but leaves a bunch of Windows DLLs untouched. Personally, I'd
prefer all DLLs to come signed, and let the developers re-sign if they
want. Removing the signatures is adding unnecessary hurdles for folks, for
no benefit I can see.
Anyway, example stacktrace:
Loading D3D native library ...
> WARNING: java.lang.UnsatisfiedLinkError: Can't load library: C:\Program
> Files\KafkIO\bin\prism_d3d.dll
> Loading library prism_d3d from resource failed:
> java.nio.file.AccessDeniedException: C:\Users\xyz
> \.openjfx\cache\23.0.2+3\amd64\prism_d3d.dll
> java.nio.file.AccessDeniedException: C:\Users\xyz
> \.openjfx\cache\23.0.2+3\amd64\prism_d3d.dll
> at
> java.base/sun.nio.fs.WindowsException.translateToIOException(Unknown Source)
> at
> java.base/sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
> at
> java.base/sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
> at
> java.base/sun.nio.fs.WindowsFileSystemProvider.implDelete(Unknown Source)
> at java.base/sun.nio.fs.AbstractFileSystemProvider.delete(Unknown
> Source)
> at java.base/java.nio.file.Files.delete(Unknown Source)
> at
> com.sun.glass.utils.NativeLibLoader.cacheLibrary(NativeLibLoader.java:300)
> at
> com.sun.glass.utils.NativeLibLoader.installLibraryFromResource(NativeLibLoader.java:218)
> at
> com.sun.glass.utils.NativeLibLoader.loadLibraryFromResource(NativeLibLoader.java:200)
> at
> com.sun.glass.utils.NativeLibLoader.loadLibraryInternal(NativeLibLoader.java:142)
> at
> com.sun.glass.utils.NativeLibLoader.loadLibrary(NativeLibLoader.java:58)
> at
> com.sun.prism.d3d.D3DPipeline.lambda$static$0(D3DPipeline.java:54)
> at java.base/java.security.AccessController.doPrivileged(Unknown
> Source)
> at com.sun.prism.d3d.D3DPipeline.<clinit>(D3DPipeline.java:50)
> at java.base/java.lang.Class.forName0(Native Method)
> at java.base/java.lang.Class.forName(Unknown Source)
> at java.base/java.lang.Class.forName(Unknown Source)
> at
> com.sun.prism.GraphicsPipeline.createPipeline(GraphicsPipeline.java:218)
> at
> com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init(QuantumRenderer.java:92)
> at
> com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125)
> at java.base/java.lang.Thread.run(Unknown Source)
> GraphicsPipeline.createPipeline failed for com.sun.prism.d3d.D3DPipeline
> java.lang.UnsatisfiedLinkError: no prism_d3d in java.library.path:
> C:\Program
> Files\KafkIO;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\Program
> Files\Oculus\Support\oculus-runtime;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;c:\dev\apps\apache-maven-3.9.9\bin;C:\dev\apps\cygwin64\bin;C:\Program Files
> (x86)\Windows Kits\10\Windows Performance Toolkit\;C:\Program
> Files\dotnet\;C:\Program Files\Git\cmd;C:\Program Files\7-Zip;C:\Program
> Files\SafeNet\Authentication\SAC\x64;C:\Program
> Files\SafeNet\Authentication\SAC\x32;C:\Program
> Files\Docker\Docker\resources\bin;%JAVA_HOME%\bin;;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Users\
> xyz\scoop\apps\zulu-jdk\current\bin;C:\Users\xyz
> \scoop\apps\zulu22-jdk\current\bin;C:\Users\xyz
> \scoop\apps\zulu21-jdk\current\bin;C:\Users\xyz \scoop\shims;C:\Users\xyz
> \AppData\Local\Microsoft\WindowsApps;C:\dev\scripts;C:\Program
> Files\JetBrains\IntelliJ IDEA 2024.2\bin;C:\Program Files\KafkIO\app;.
> at java.base/java.lang.ClassLoader.loadLibrary(Unknown Source)
> at java.base/java.lang.Runtime.loadLibrary0(Unknown Source)
> at java.base/java.lang.System.loadLibrary(Unknown Source)
> at
> com.sun.glass.utils.NativeLibLoader.loadLibraryInternal(NativeLibLoader.java:170)
> at
> com.sun.glass.utils.NativeLibLoader.loadLibrary(NativeLibLoader.java:58)
> at
> com.sun.prism.d3d.D3DPipeline.lambda$static$0(D3DPipeline.java:54)
> at java.base/java.security.AccessController.doPrivileged(Unknown
> Source)
> at com.sun.prism.d3d.D3DPipeline.<clinit>(D3DPipeline.java:50)
> at java.base/java.lang.Class.forName0(Native Method)
> at java.base/java.lang.Class.forName(Unknown Source)
> at java.base/java.lang.Class.forName(Unknown Source)
> at
> com.sun.prism.GraphicsPipeline.createPipeline(GraphicsPipeline.java:218)
> at
> com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init(QuantumRenderer.java:92)
> at
> com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125)
> at java.base/java.lang.Thread.run(Unknown Source)
Kind Regards,
Cormac
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/openjfx-dev/attachments/20250206/c1d85b68/attachment-0001.htm>
More information about the openjfx-dev
mailing list