mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
JBR-4839 Report if wrong shared library is detected at run time
(cherry picked from commit e8c1913562)
This commit is contained in:
@@ -24,6 +24,8 @@
|
||||
*/
|
||||
|
||||
#import <jni.h>
|
||||
#import <mach-o/dyld.h>
|
||||
#import <jni_util.h>
|
||||
|
||||
#import "InitIDs.h"
|
||||
|
||||
@@ -161,3 +163,26 @@ JNIEXPORT void JNICALL Java_java_awt_event_MouseEvent_initIDs
|
||||
(JNIEnv *env, jclass cls)
|
||||
{
|
||||
}
|
||||
|
||||
JNIEXPORT jarray JNICALL Java_sun_font_FontManagerNativeLibrary_loadedLibraries
|
||||
(JNIEnv *env, jclass cls)
|
||||
{
|
||||
const uint32_t count = _dyld_image_count();
|
||||
|
||||
jclass stringClazz = (*env)->FindClass(env, "java/lang/String");
|
||||
CHECK_NULL_RETURN(stringClazz, NULL);
|
||||
jarray libsArray = (*env)->NewObjectArray(env, count, stringClazz, NULL);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
const char * name = _dyld_get_image_name(i);
|
||||
if (name) {
|
||||
jstring jName = (*env)->NewStringUTF(env, name);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
|
||||
(*env)->SetObjectArrayElement(env, libsArray, i, jName);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return libsArray;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,10 @@
|
||||
package sun.font;
|
||||
|
||||
import sun.awt.OSInfo;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Set;
|
||||
|
||||
@SuppressWarnings("restricted")
|
||||
public class FontManagerNativeLibrary {
|
||||
@@ -53,6 +57,8 @@ public class FontManagerNativeLibrary {
|
||||
System.loadLibrary("freetype");
|
||||
}
|
||||
System.loadLibrary("fontmanager");
|
||||
|
||||
checkLibraries();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -63,4 +69,72 @@ public class FontManagerNativeLibrary {
|
||||
* Actual loading is performed by static initializer.
|
||||
*/
|
||||
public static void load() {}
|
||||
|
||||
|
||||
private static class Holder {
|
||||
private static final PlatformLogger errorLog = PlatformLogger.getLogger("sun.font.FontManagerNativeLibrary");
|
||||
}
|
||||
public static void checkLibraries() {
|
||||
final String osName = System.getProperty("os.name");
|
||||
final boolean isMacOS = osName.startsWith("Mac");
|
||||
final boolean isLinux = osName.startsWith("Linux");
|
||||
|
||||
if (!(isMacOS || isLinux)) return;
|
||||
|
||||
final String[] loadedLibraries = loadedLibraries();
|
||||
|
||||
final String libawtName = isMacOS ? "libawt.dylib" : "libawt.so";
|
||||
final String bootPath = System.getProperty("sun.boot.library.path");
|
||||
final Path basePath = bootPath != null
|
||||
? Path.of(bootPath)
|
||||
: getBasePath(libawtName, loadedLibraries);
|
||||
|
||||
if (basePath == null) {
|
||||
// Nothing to check if the native code failed to report where libawt is
|
||||
return;
|
||||
}
|
||||
|
||||
final String libraryPathEnvVarName = isMacOS
|
||||
? "DYLD_LIBRARY_PATH"
|
||||
: "LD_LIBRARY_PATH";
|
||||
final Set<String> ourLibraries = isMacOS
|
||||
? Set.of("libawt_lwawt.dylib", "libfontmanager.dylib", "libfreetype.dylib")
|
||||
: Set.of("libawt_xawt.so", "libfontmanager.so");
|
||||
|
||||
boolean warnedAlready = false;
|
||||
for (String pathName: loadedLibraries) {
|
||||
if (pathName == null)
|
||||
continue;
|
||||
final Path libPath = Path.of(pathName);
|
||||
final Path libFileName = libPath.getFileName();
|
||||
if (ourLibraries.contains(libFileName.toString())) {
|
||||
final Path libDirectory = libPath.getParent();
|
||||
if (!basePath.equals(libDirectory)) {
|
||||
Holder.errorLog.severe("Library '" + libFileName +
|
||||
"' loaded from '" + libDirectory + "' instead of '" +
|
||||
basePath + "'");
|
||||
if (!warnedAlready) {
|
||||
warnedAlready = true;
|
||||
final String libraryPathOverride = System.getenv(libraryPathEnvVarName);
|
||||
if (libraryPathOverride != null) {
|
||||
Holder.errorLog.severe("Note: " + libraryPathEnvVarName +
|
||||
" is set to '" + libraryPathOverride + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Path getBasePath(String libawtName, String[] libs) {
|
||||
Path basePath = null;
|
||||
for (String path: libs) {
|
||||
if (path.endsWith(libawtName)) {
|
||||
basePath = Path.of(path).getParent().normalize();
|
||||
}
|
||||
}
|
||||
return basePath;
|
||||
}
|
||||
|
||||
private static native String[] loadedLibraries();
|
||||
}
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
|
||||
#include "jni_util.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <link.h>
|
||||
|
||||
/*
|
||||
* This file contains stubs for JNI field and method id initializers
|
||||
* which are used in the win32 awt.
|
||||
@@ -91,3 +95,72 @@ Java_java_awt_event_MouseEvent_initIDs
|
||||
(JNIEnv *env, jclass clazz)
|
||||
{
|
||||
}
|
||||
|
||||
struct shared_libs {
|
||||
int count;
|
||||
int index;
|
||||
char ** names;
|
||||
};
|
||||
|
||||
static int
|
||||
dl_iterate_callback
|
||||
(struct dl_phdr_info *info, size_t size, void *data)
|
||||
{
|
||||
struct shared_libs *libs = (struct shared_libs*)data;
|
||||
if (libs->names == NULL) {
|
||||
libs->count++;
|
||||
} else {
|
||||
// The number of libraries may have grown since the last time we asked.
|
||||
if (libs->index < libs->count) {
|
||||
libs->names[libs->index++] = strdup(info->dlpi_name);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static jarray
|
||||
convert_to_java_array
|
||||
(JNIEnv *env, struct shared_libs* libs)
|
||||
{
|
||||
jclass stringClazz = (*env)->FindClass(env, "java/lang/String");
|
||||
CHECK_NULL_RETURN(stringClazz, NULL);
|
||||
jarray libsArray = (*env)->NewObjectArray(env, libs->count, stringClazz, NULL);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
|
||||
|
||||
for (uint32_t i = 0; i < libs->count; i++) {
|
||||
const char * name = libs->names[i];
|
||||
if (name) {
|
||||
jstring jName = (*env)->NewStringUTF(env, name);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
|
||||
(*env)->SetObjectArrayElement(env, libsArray, i, jName);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return libsArray;
|
||||
}
|
||||
|
||||
JNIEXPORT jarray JNICALL
|
||||
Java_sun_font_FontManagerNativeLibrary_loadedLibraries
|
||||
(JNIEnv *env, jclass cls)
|
||||
{
|
||||
struct shared_libs libs = {0, 0, NULL};
|
||||
dl_iterate_phdr(&dl_iterate_callback, &libs);
|
||||
if (libs.count <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
libs.names = (char **) calloc(libs.count, sizeof(libs.names[0]));
|
||||
CHECK_NULL_RETURN(libs.names, NULL);
|
||||
dl_iterate_phdr(&dl_iterate_callback, &libs);
|
||||
|
||||
jarray libsArray = convert_to_java_array(env, &libs);
|
||||
|
||||
for (uint32_t i = 0; i < libs.count; i++) {
|
||||
free(libs.names[i]);
|
||||
}
|
||||
free(libs.names);
|
||||
|
||||
return libsArray;
|
||||
}
|
||||
|
||||
104
test/jdk/jb/java/awt/Font/LibrariesCheck.java
Normal file
104
test/jdk/jb/java/awt/Font/LibrariesCheck.java
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 2022, JetBrains s.r.o.. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @summary Verifies that a warning is issued when certain bundled libraries
|
||||
* are loaded NOT from 'test.jdk'.
|
||||
* @requires os.family == "mac"
|
||||
* @library /test/lib
|
||||
* @run main LibrariesCheck
|
||||
*/
|
||||
|
||||
import java.awt.Robot;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.JLabel;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.Platform;
|
||||
|
||||
public class LibrariesCheck {
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length > 0 && args[0].equals("runtest")) {
|
||||
LibrariesCheck test = new LibrariesCheck();
|
||||
} else {
|
||||
// Run the test with DYLD_LIBRARY_PATH pointing to a directory
|
||||
// with a substitute libfontmanager. JBR is supposed to detect this
|
||||
// and complain with a log message.
|
||||
String dynamicLibPathEnvVarName = "DYLD_LIBRARY_PATH";
|
||||
Path tempDir = Files.createTempDirectory(LibrariesCheck.class.getName());
|
||||
String testLibName = System.mapLibraryName("fontmanager");
|
||||
Path testLibPath = tempDir.resolve(testLibName);
|
||||
try {
|
||||
Path jdkLibPath = Platform.libDir();
|
||||
Files.copy(jdkLibPath.resolve(testLibName), testLibPath);
|
||||
|
||||
ProcessBuilder pb = ProcessTools.createTestJvm(
|
||||
LibrariesCheck.class.getName(),
|
||||
"runtest");
|
||||
|
||||
Map<String, String> env = pb.environment();
|
||||
env.put(dynamicLibPathEnvVarName, tempDir.toString());
|
||||
|
||||
OutputAnalyzer oa = ProcessTools.executeProcess(pb);
|
||||
oa.shouldContain("SEVERE").shouldContain(testLibName)
|
||||
.shouldContain(dynamicLibPathEnvVarName);
|
||||
} finally {
|
||||
Files.delete(testLibPath);
|
||||
Files.delete(tempDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JFrame frame;
|
||||
|
||||
LibrariesCheck() throws Exception {
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
frame = new JFrame("LibrariesCheck");
|
||||
JPanel panel = new JPanel();
|
||||
panel.add(new JLabel("some text"));
|
||||
frame.getContentPane().add(panel);
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
});
|
||||
|
||||
Robot robot = new Robot();
|
||||
robot.waitForIdle();
|
||||
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
frame.dispose();
|
||||
});
|
||||
} finally {
|
||||
if (frame != null) {
|
||||
frame.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user