diff --git a/CHANGELOG.md b/CHANGELOG.md index fda3fec2..b1714e11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ FlatLaf Change Log - `FlatSVGIcon` color filters now support linear gradients. (PR #817) - Added support for `JSplitPane.expandableSide` client property to `FlatSplitPane`. +- Native libraries: Added API version check to test whether native library + matches the JAR (bad builds could e.g. ship a newer JAR with an older + incompatible native library) and to test whether native methods can be invoked + (some security software allows loading native library but blocks method + invocation). ## 3.4 diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLibrary.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLibrary.java index 5ffc2a6a..3c169c28 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLibrary.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLibrary.java @@ -37,16 +37,18 @@ class FlatNativeLibrary private static boolean initialized; private static NativeLibrary nativeLibrary; + private native static int getApiVersion(); + /** * Loads native library (if available) and returns whether loaded successfully. * Returns {@code false} if no native library is available. */ - static synchronized boolean isLoaded() { - initialize(); + static synchronized boolean isLoaded( int apiVersion ) { + initialize( apiVersion ); return (nativeLibrary != null) ? nativeLibrary.isLoaded() : false; } - private static void initialize() { + private static void initialize( int apiVersion ) { if( initialized ) return; initialized = true; @@ -104,7 +106,26 @@ class FlatNativeLibrary return; // no native library available for current OS or CPU architecture // load native library - nativeLibrary = createNativeLibrary( classifier, ext ); + NativeLibrary nativeLibrary = createNativeLibrary( classifier, ext ); + if( !nativeLibrary.isLoaded() ) + return; + + // check API version (and check whether library works) + try { + int actualApiVersion = getApiVersion(); + if( actualApiVersion != apiVersion ) { + LoggingFacade.INSTANCE.logSevere( "FlatLaf: Wrong API version in native library (expected " + + apiVersion + ", actual " + actualApiVersion + "). Ignoring native library.", null ); + return; + } + } catch( Throwable ex ) { + // could be a UnsatisfiedLinkError in case that loading native library + // from temp directory was blocked by some OS security mechanism + LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to get API version of native library. Ignoring native library.", ex ); + return; + } + + FlatNativeLibrary.nativeLibrary = nativeLibrary; } private static NativeLibrary createNativeLibrary( String classifier, String ext ) { @@ -118,9 +139,9 @@ class FlatNativeLibrary if( library.isLoaded() ) return library; - LoggingFacade.INSTANCE.logSevere( "Did not find library '" + System.mapLibraryName( libraryName ) - + "' in java.library.path '" + System.getProperty( "java.library.path" ) - + "', using extracted library instead", null ); + LoggingFacade.INSTANCE.logSevere( "FlatLaf: Native library '" + System.mapLibraryName( libraryName ) + + "' not found in java.library.path '" + System.getProperty( "java.library.path" ) + + "'. Using extracted native library instead.", null ); } else { // try standard library naming scheme // (same as in flatlaf.jar in package 'com/formdev/flatlaf/natives') @@ -139,11 +160,11 @@ class FlatNativeLibrary return new NativeLibrary( libraryFile2, true ); } - LoggingFacade.INSTANCE.logSevere( "Did not find library '" + LoggingFacade.INSTANCE.logSevere( "FlatLaf: Native library '" + libraryFile.getName() + (libraryName2 != null ? ("' or '" + libraryName2) : "") - + "' in '" + libraryFile.getParentFile().getAbsolutePath() - + "', using extracted library instead", null ); + + "' not found in '" + libraryFile.getParentFile().getAbsolutePath() + + "'. Using extracted native library instead.", null ); } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLinuxLibrary.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLinuxLibrary.java index b60922ec..8f0ee8b3 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLinuxLibrary.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLinuxLibrary.java @@ -35,6 +35,8 @@ import com.formdev.flatlaf.util.SystemInfo; */ class FlatNativeLinuxLibrary { + private static int API_VERSION_LINUX = 3001; + /** * Checks whether native library is loaded/available. *
@@ -42,7 +44,7 @@ class FlatNativeLinuxLibrary * method of this class. Otherwise, the native library may not be loaded. */ static boolean isLoaded() { - return SystemInfo.isLinux && FlatNativeLibrary.isLoaded(); + return SystemInfo.isLinux && FlatNativeLibrary.isLoaded( API_VERSION_LINUX ); } // direction for _NET_WM_MOVERESIZE message diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java index 0ef75f50..7d08376a 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java @@ -44,6 +44,8 @@ import com.formdev.flatlaf.util.SystemInfo; */ public class FlatNativeMacLibrary { + private static int API_VERSION_MACOS = 2001; + /** * Checks whether native library is loaded/available. *
@@ -51,7 +53,7 @@ public class FlatNativeMacLibrary
* method of this class. Otherwise, the native library may not be loaded.
*/
public static boolean isLoaded() {
- return SystemInfo.isMacOS && FlatNativeLibrary.isLoaded();
+ return SystemInfo.isMacOS && FlatNativeLibrary.isLoaded( API_VERSION_MACOS );
}
public native static boolean setWindowRoundedBorder( Window window, float radius, float borderWidth, int borderColor );
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowsLibrary.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowsLibrary.java
index 669271e6..8a4ce3cf 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowsLibrary.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowsLibrary.java
@@ -30,6 +30,8 @@ import com.formdev.flatlaf.util.SystemInfo;
*/
public class FlatNativeWindowsLibrary
{
+ private static int API_VERSION_WINDOWS = 1001;
+
private static long osBuildNumber = Long.MIN_VALUE;
/**
@@ -39,7 +41,7 @@ public class FlatNativeWindowsLibrary
* method of this class. Otherwise, the native library may not be loaded.
*/
public static boolean isLoaded() {
- return SystemInfo.isWindows && FlatNativeLibrary.isLoaded();
+ return SystemInfo.isWindows && FlatNativeLibrary.isLoaded( API_VERSION_WINDOWS );
}
/**
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatWindowsNativeWindowBorder.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatWindowsNativeWindowBorder.java
index dda40c28..a4014001 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatWindowsNativeWindowBorder.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatWindowsNativeWindowBorder.java
@@ -89,7 +89,7 @@ class FlatWindowsNativeWindowBorder
return null;
// check whether native library was successfully loaded
- if( !FlatNativeLibrary.isLoaded() )
+ if( !FlatNativeWindowsLibrary.isLoaded() )
return null;
// create new instance
diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-arm64.dll b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-arm64.dll
index b9c9aaa8..ea7d69bd 100644
Binary files a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-arm64.dll and b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-arm64.dll differ
diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-x86.dll b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-x86.dll
index e2b447e2..37c592cd 100644
Binary files a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-x86.dll and b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-x86.dll differ
diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-x86_64.dll b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-x86_64.dll
index 1afddbf9..d3ccf1b6 100644
Binary files a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-x86_64.dll and b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-x86_64.dll differ
diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-linux-x86_64.so b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-linux-x86_64.so
index 9942ff5c..3d0ddc5a 100644
Binary files a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-linux-x86_64.so and b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-linux-x86_64.so differ
diff --git a/flatlaf-natives/flatlaf-natives-linux/build.gradle.kts b/flatlaf-natives/flatlaf-natives-linux/build.gradle.kts
index 4fcb9838..a81d6643 100644
--- a/flatlaf-natives/flatlaf-natives-linux/build.gradle.kts
+++ b/flatlaf-natives/flatlaf-natives-linux/build.gradle.kts
@@ -21,7 +21,10 @@ plugins {
}
flatlafJniHeaders {
- headers = listOf( "com_formdev_flatlaf_ui_FlatNativeLinuxLibrary.h" )
+ headers = listOf(
+ "com_formdev_flatlaf_ui_FlatNativeLibrary.h",
+ "com_formdev_flatlaf_ui_FlatNativeLinuxLibrary.h"
+ )
}
library {
diff --git a/flatlaf-natives/flatlaf-natives-linux/src/main/cpp/ApiVersion.cpp b/flatlaf-natives/flatlaf-natives-linux/src/main/cpp/ApiVersion.cpp
new file mode 100644
index 00000000..02454fb3
--- /dev/null
+++ b/flatlaf-natives/flatlaf-natives-linux/src/main/cpp/ApiVersion.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2024 FormDev Software GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include