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: credm...@certak.com | m: +353 (0) 86 268 2152 | w: www.certak.com <http://www.certak.com>



On Thu, 6 Feb 2025 at 19:56, Cormac Redmond <credm...@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\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

Reply via email to