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
Sat Feb 8 17:35:00 UTC 2025
Hi,
Thanks for the reply. Yes -- my project uses JFX JARs rather than jmods (as
many do). And the clashing application in question, must be the same. But
this is a real problem that occurred with a real user, and I only have a
handful of users.
Oracle signing the JFX DLLs, while an improvement, would still leave the
following problems wide open:
- There's no way to stop a developer (or some build tool) from
re-signing or removing signature from signed DLLs, in which case this
problem can still re-occur
- In the event of a genuine difference of a DLLs (under the same cache
folder version), if the DLL cannot be deleted (to be replaced), because a
running application application is using it -- a completely feasibly
scenario -- then we have one application breaking another.
Also, the developers shipping apps are in full control of the JFX JARs,
their DLLs, and the *reported" javafx.version and javafx.runtime.version.
E.g., I could have JFX 21.0.5 in a JFX 23.0.2 cache folder if I wanted
simply by changing javafx.runtime.version (or javafx.cachedir).
It's far too brittle.
Regards,
*Cormac Redmond*
Software Engineer, Certak Ltd.
e: credmond at certak.com | m: +353 (0) 86 268 2152 | w: www.certak.com
On Sat, 8 Feb 2025 at 12:49, Christopher Schnick <crschnick at xpipe.io> wrote:
> I think that went a bit under the radar as this only occurs when using the
> maven dependencies. The SDK and jmod downloads do not have that issue as
> they don't copy DLLs into any temp directory. Only the maven jars have to
> do this.
>
> About signing any JavaFX DLLs, that would indeed be a good addition
> considering all other JDK DLLs are signed.
>
> Best
> Christopher Schnick
> On 08/02/2025 13:31, Cormac Redmond wrote:
>
> Hi,
>
> I am surprised nobody else sees this bug as a higher-priority conversation
> point.
>
> It's troubling to see how running one self-contained application can break
> another self-contained application (because of a cache that most JFX devs
> wouldn't even know exist).
>
> If one well-behaved JFX application cannot delete/replace a file JFX cache
> on start-up, because another well-behaved JFX application is using that
> cached file (it will be if built on the same JFX version) -- then the
> application will not run, at all.
>
> And as I explained earlier, this is a likely occurring scenario in the
> wild -- the only reason this bug isn't more prevalent /reported /
> noticeable, is that it's not too likely for a user to have two JFX
> applications using the same JavaFX version, on their machine. But that's
> down to pure coincidence / chance. I wouldn't say the same for Electron or
> Flutter, etc. If they had this bug, it would be noticed and it would be
> news.
>
> Also, the creators of these applications would have no idea that their
> application is not starting, nor would the users know why.
>
> By the way, the problem is not just about *signed* DLLs + checksums,
> obviously. It would occur if the DLLs are different for any other
> reason too, obviously, and the authors of NativeLibLoader thought this
> possibility is high enough to do the checksum + delete + replace check. The
> application shouldn't silently fail because of a cache management bug.
>
>
>
>
> Regards,
>
> *Cormac Redmond*
> Software Engineer, Certak Ltd.
>
> e: credmond at certak.com | m: +353 (0) 86 268 2152 | w: www.certak.com
>
>
>
> On Thu, 6 Feb 2025 at 19:56, Cormac Redmond <credmond at certak.com> wrote:
>
>> 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\x
>>> yz \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/20250208/e0443f8c/attachment-0001.htm>
More information about the openjfx-dev
mailing list