diff options
author | Sven Gothel <[email protected]> | 2023-11-26 09:49:12 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-11-26 09:49:12 +0100 |
commit | c7efca6d9b0db7305f5352ebf15d915ae5a1fa24 (patch) | |
tree | 7ba72733c9296aea5ea339b3fd81d264b49d3e8c /src/java/com/jogamp/common/os | |
parent | aea14464d521dca28165498ffe943ef1122fc2e3 (diff) |
Bug 1479: NativeLibrary: Add getNativeLibraryPath() returning queried used native library path, supported throughout DynamicLibraryBundle[Info]
Motivation: It is helpful to retrieve the actually used native library pathname,
since loading a library w/o absolute path but lookup through LD_LIBRARY_PATH
may render it hard for the user to determine which library is used.
+++
+++
Windows implementation simply can use GetModuleFileNameA() with the native library handle.
POSIX implementation may utilize a symbol-name to retrieve its address within the
loading native library used to retrieved the library information
via dladdr().
To support this feature throughout DynamicLibraryBundle and DynamicLibraryBundleInfo,
the custom DynamicLibraryBundleInfo specializations shall provide
optional symbol-names per each tool-library-name for the POSIX implementation,
see above.
public interface DynamicLibraryBundleInfo {
...
/**
* Returns optional list of optional symbol names per {@link #getToolLibNames()}
* in same order for an OS which requires the symbol's address to retrieve
* the path of the containing library.
*/
public List<String> getSymbolForToolLibPath();
...
}
Diffstat (limited to 'src/java/com/jogamp/common/os')
4 files changed, 133 insertions, 60 deletions
diff --git a/src/java/com/jogamp/common/os/DynamicLibraryBundle.java b/src/java/com/jogamp/common/os/DynamicLibraryBundle.java index fee3c01..a513ec4 100644 --- a/src/java/com/jogamp/common/os/DynamicLibraryBundle.java +++ b/src/java/com/jogamp/common/os/DynamicLibraryBundle.java @@ -1,5 +1,5 @@ /** - * Copyright 2010 JogAmp Community. All rights reserved. + * Copyright 2010-2023 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: @@ -61,11 +61,12 @@ import com.jogamp.common.util.RunnableExecutor; public class DynamicLibraryBundle implements DynamicLookupHelper { private final DynamicLibraryBundleInfo info; - protected final List<NativeLibrary> nativeLibraries; - private final DynamicLinker dynLinkGlobal; private final List<List<String>> toolLibNames; + protected final List<NativeLibrary> toolLibraries; + private final List<String> toolLibSymbolNames; private final List<String> glueLibNames; private final boolean[] toolLibLoaded; + private final DynamicLinker dynLinkGlobal; private int toolLibLoadedNumber; @@ -97,8 +98,9 @@ public class DynamicLibraryBundle implements DynamicLookupHelper { if(DEBUG) { System.err.println(Thread.currentThread().getName()+" - DynamicLibraryBundle.init start with: "+info.getClass().getName()); } - nativeLibraries = new ArrayList<NativeLibrary>(); toolLibNames = info.getToolLibNames(); + toolLibraries = new ArrayList<NativeLibrary>(toolLibNames.size()); + toolLibSymbolNames = info.getSymbolForToolLibPath(); glueLibNames = info.getGlueLibNames(); toolLibLoaded = new boolean[toolLibNames.size()]; if(DEBUG) { @@ -143,7 +145,9 @@ public class DynamicLibraryBundle implements DynamicLookupHelper { System.err.println("DynamicLibraryBundle.init Summary: "+info.getClass().getName()); System.err.println(" toolGetProcAddressFuncNameList: "+toolGetProcAddressFuncNameList+", complete: "+toolGetProcAddressComplete+", 0x"+Long.toHexString(toolGetProcAddressHandle)); System.err.println(" Tool Lib Names : "+toolLibNames); + System.err.println(" Tool Lib Symbol: "+toolLibSymbolNames); System.err.println(" Tool Lib Loaded: "+getToolLibLoadedNumber()+"/"+getToolLibNumber()+" "+Arrays.toString(toolLibLoaded)+", complete "+isToolLibComplete()); + System.err.println(" Tool Libraries : "+toolLibraries); System.err.println(" Glue Lib Names : "+glueLibNames); System.err.println(" Glue Lib Loaded: "+getGlueLibLoadedNumber()+"/"+getGlueLibNumber()+" "+Arrays.toString(glueLibLoaded)+", complete "+isGlueLibComplete()); System.err.println(" All Complete: "+isLibComplete()); @@ -159,10 +163,13 @@ public class DynamicLibraryBundle implements DynamicLookupHelper { toolGetProcAddressFuncNameSet = null; toolGetProcAddressHandle = 0; toolGetProcAddressComplete = false; - for(int i = 0; i<nativeLibraries.size(); i++) { - nativeLibraries.get(i).close(); + for(int i = 0; i<toolLibraries.size(); i++) { + final NativeLibrary lib = toolLibraries.get(i); + if( null != lib ) { + lib.close(); + } } - nativeLibraries.clear(); + toolLibraries.clear(); toolLibNames.clear(); glueLibNames.clear(); if(DEBUG) { @@ -206,6 +213,12 @@ public class DynamicLibraryBundle implements DynamicLookupHelper { return false; } + /** + * Returns list of {@link NativeLibrary}s for each {@link DynamicLibraryBundleInfo#getToolLibNames()} in the same size and order. + * May contain elements with {@code null} for not loaded libs. + */ + public final List<NativeLibrary> getToolLibraries() { return toolLibraries; } + public final int getGlueLibNumber() { return glueLibNames.size(); } @@ -252,9 +265,9 @@ public class DynamicLibraryBundle implements DynamicLookupHelper { protected static final NativeLibrary loadFirstAvailable(final List<String> libNames, final boolean searchSystemPath, final boolean searchSystemPathFirst, - final ClassLoader loader, final boolean global) throws SecurityException { + final ClassLoader loader, final boolean global, final String symbolName) throws SecurityException { for (int i=0; i < libNames.size(); i++) { - final NativeLibrary lib = NativeLibrary.open(libNames.get(i), searchSystemPath, searchSystemPathFirst, loader, global); + final NativeLibrary lib = NativeLibrary.open(libNames.get(i), searchSystemPath, searchSystemPathFirst, loader, global, symbolName); if (lib != null) { return lib; } @@ -271,11 +284,13 @@ public class DynamicLibraryBundle implements DynamicLookupHelper { for (i=0; i < toolLibNames.size(); i++) { final List<String> libNames = toolLibNames.get(i); + final String symbolName = toolLibSymbolNames.get(i); if( null != libNames && libNames.size() > 0 ) { lib = loadFirstAvailable(libNames, info.searchToolLibInSystemPath(), info.searchToolLibSystemPathFirst(), - cl, info.shallLinkGlobal()); + cl, info.shallLinkGlobal(), symbolName); + toolLibraries.add(lib); if ( null == lib ) { if(DEBUG) { System.err.println("Unable to load any Tool library of: "+libNames); @@ -284,13 +299,14 @@ public class DynamicLibraryBundle implements DynamicLookupHelper { if( null == dynLinkGlobal ) { dynLinkGlobal = lib.dynamicLinker(); } - nativeLibraries.add(lib); - toolLibLoaded[i]=true; + toolLibLoaded[i] = true; toolLibLoadedNumber++; if(DEBUG) { System.err.println("Loaded Tool library: "+lib); } } + } else { + toolLibraries.add(null); // same size and order as toolLibNames! } } if( toolLibNames.size() > 0 && !isToolLibLoaded() ) { @@ -347,16 +363,19 @@ public class DynamicLibraryBundle implements DynamicLookupHelper { addr = dynLinkGlobal.lookupSymbolGlobal(funcName); } // Look up this function name in all known libraries - for (int i=0; 0==addr && i < nativeLibraries.size(); i++) { - lib = nativeLibraries.get(i); - addr = lib.dynamicLookupFunction(funcName); + for (int i=0; 0==addr && i < toolLibraries.size(); i++) { + final NativeLibrary lib0 = toolLibraries.get(i); + if( null != lib0 ) { + lib = lib0; + addr = lib0.dynamicLookupFunction(funcName); + } } if(DEBUG_LOOKUP) { final String libName = ( null == lib ) ? "GLOBAL" : lib.toString(); if(0!=addr) { System.err.println("Lookup-Native: <" + funcName + "> 0x" + Long.toHexString(addr) + " in lib " + libName ); } else { - System.err.println("Lookup-Native: <" + funcName + "> ** FAILED ** in libs " + nativeLibraries); + System.err.println("Lookup-Native: <" + funcName + "> ** FAILED ** in libs " + toolLibraries); } } return addr; @@ -377,14 +396,20 @@ public class DynamicLibraryBundle implements DynamicLookupHelper { @Override public final void claimAllLinkPermission() throws SecurityException { - for (int i=0; i < nativeLibraries.size(); i++) { - nativeLibraries.get(i).claimAllLinkPermission(); + for(int i = 0; i<toolLibraries.size(); i++) { + final NativeLibrary lib = toolLibraries.get(i); + if( null != lib ) { + lib.claimAllLinkPermission(); + } } } @Override public final void releaseAllLinkPermission() throws SecurityException { - for (int i=0; i < nativeLibraries.size(); i++) { - nativeLibraries.get(i).releaseAllLinkPermission(); + for(int i = 0; i<toolLibraries.size(); i++) { + final NativeLibrary lib = toolLibraries.get(i); + if( null != lib ) { + lib.releaseAllLinkPermission(); + } } } diff --git a/src/java/com/jogamp/common/os/DynamicLibraryBundleInfo.java b/src/java/com/jogamp/common/os/DynamicLibraryBundleInfo.java index 01068b4..0d9f1f8 100644 --- a/src/java/com/jogamp/common/os/DynamicLibraryBundleInfo.java +++ b/src/java/com/jogamp/common/os/DynamicLibraryBundleInfo.java @@ -1,5 +1,5 @@ /** - * Copyright 2010 JogAmp Community. All rights reserved. + * Copyright 2010-2023 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: @@ -65,6 +65,11 @@ public interface DynamicLibraryBundleInfo { public List<List<String>> getToolLibNames(); /** + * Returns optional list of optional symbol names per {@link #getToolLibNames()} in same order for an OS which requires the symbol's address to retrieve the path of the containing library. + */ + public List<String> getSymbolForToolLibPath(); + + /** * If a {@link SecurityManager} is installed, user needs link permissions * for the named libraries. * diff --git a/src/java/com/jogamp/common/os/DynamicLinker.java b/src/java/com/jogamp/common/os/DynamicLinker.java index 4019c77..7b12aee 100644 --- a/src/java/com/jogamp/common/os/DynamicLinker.java +++ b/src/java/com/jogamp/common/os/DynamicLinker.java @@ -1,5 +1,5 @@ /** - * Copyright 2013 JogAmp Community. All rights reserved. + * Copyright 2013-2023 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: @@ -72,6 +72,19 @@ public interface DynamicLinker { public long openLibraryLocal(String pathname, boolean debug) throws SecurityException; /** + * Security checks are implicit by previous call of + * {@link #openLibraryLocal(String, boolean)} or {@link #openLibraryGlobal(String, boolean)} + * retrieving the <code>librarHandle</code>. + * + * @param libraryHandle a library handle previously retrieved via {@link #openLibraryLocal(String, boolean)} or {@link #openLibraryGlobal(String, boolean)}. + * @param symbolName optional symbol name for an OS which requires the symbol's address to retrieve the path of the containing library + * @return the library pathname if found and supported by OS or {@code null}. + * @throws IllegalArgumentException in case case <code>libraryHandle</code> is unknown. + * @throws SecurityException if user is not granted access for the given library handle + */ + public String lookupLibraryPathname(long libraryHandle, String symbolName) throws SecurityException; + + /** * If a {@link SecurityManager} is installed, user needs link permissions * for <b>all</b> libraries, i.e. for <code>new RuntimePermission("loadLibrary.*");</code>! * diff --git a/src/java/com/jogamp/common/os/NativeLibrary.java b/src/java/com/jogamp/common/os/NativeLibrary.java index 53db784..e00599c 100644 --- a/src/java/com/jogamp/common/os/NativeLibrary.java +++ b/src/java/com/jogamp/common/os/NativeLibrary.java @@ -1,41 +1,30 @@ -/* - * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. - * Copyright (c) 2011 JogAmp Community. All rights reserved. +/** + * Copyright 2011-2023 JogAmp Community. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed or intended for use - * in the design, construction, operation or maintenance of any nuclear - * facility. - * - * Sun gratefully acknowledges that this software was originally authored - * and developed by Kenneth Bradley Russell and Christopher John Kline. + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. */ package com.jogamp.common.os; @@ -126,13 +115,17 @@ public final class NativeLibrary implements DynamicLookupHelper { // May as well keep around the path to the library we opened private final String libraryPath; + // Native library path of the opened native libraryHandle, maybe null + private final String nativeLibraryPath; + private final boolean global; // Private constructor to prevent arbitrary instances from floating around - private NativeLibrary(final DynamicLinker dynLink, final long libraryHandle, final String libraryPath, final boolean global) { + private NativeLibrary(final DynamicLinker dynLink, final long libraryHandle, final String libraryPath, final boolean global, final String symbolName) { this.dynLink = dynLink; this.libraryHandle = libraryHandle; this.libraryPath = libraryPath; + this.nativeLibraryPath = dynLink.lookupLibraryPathname(libraryHandle, symbolName); this.global = global; if (DEBUG) { System.err.println("NativeLibrary.open(): Successfully loaded: " + this); @@ -141,7 +134,9 @@ public final class NativeLibrary implements DynamicLookupHelper { @Override public final String toString() { - return "NativeLibrary[" + dynLink.getClass().getSimpleName() + ", " + libraryPath + ", 0x" + Long.toHexString(libraryHandle) + ", global " + global + "]"; + final String nlp_s = null != nativeLibraryPath ? ", native '"+nativeLibraryPath+"'" : ""; + return "NativeLibrary[" + dynLink.getClass().getSimpleName() + ", path[given '" + libraryPath + "'"+nlp_s+"], 0x" + + Long.toHexString(libraryHandle) + ", global " + global + "]"; } /** @@ -198,7 +193,36 @@ public final class NativeLibrary implements DynamicLookupHelper { final boolean searchSystemPath, final boolean searchSystemPathFirst, final ClassLoader loader, final boolean global) throws SecurityException { - return open(libName, libName, libName, searchSystemPath, searchSystemPathFirst, loader, global); + return open(libName, libName, libName, searchSystemPath, searchSystemPathFirst, loader, global, null); + } + + /** Opens the given native library, assuming it has the same base + name on all platforms. + <p> + The {@code searchSystemPath} argument changes the behavior to + either use the default system path or not at all. + </p> + <p> + Assuming {@code searchSystemPath} is {@code true}, + the {@code searchSystemPathFirst} argument changes the behavior to first + search the default system path rather than searching it last. + </p> + * @param libName library name, with or without prefix and suffix + * @param searchSystemPath if {@code true} library shall be searched in the system path <i>(default)</i>, otherwise {@code false}. + * @param searchSystemPathFirst if {@code true} system path shall be searched <i>first</i> <i>(default)</i>, rather than searching it last. + * if {@code searchSystemPath} is {@code false} this argument is ignored. + * @param loader {@link ClassLoader} to locate the library + * @param global if {@code true} allows system wide access of the loaded library, otherwise access is restricted to the process. + * @param symbolName optional symbol name for an OS which requires the symbol's address to retrieve the path of the containing library + * @return {@link NativeLibrary} instance or {@code null} if library could not be loaded. + * @throws SecurityException if user is not granted access for the named library. + * @since 2.4.0 + */ + public static final NativeLibrary open(final String libName, + final boolean searchSystemPath, + final boolean searchSystemPathFirst, + final ClassLoader loader, final boolean global, final String symbolName) throws SecurityException { + return open(libName, libName, libName, searchSystemPath, searchSystemPathFirst, loader, global, symbolName); } /** Opens the given native library, assuming it has the given base @@ -230,6 +254,7 @@ public final class NativeLibrary implements DynamicLookupHelper { * if {@code searchSystemPath} is {@code false} this argument is ignored. * @param loader {@link ClassLoader} to locate the library * @param global if {@code true} allows system wide access of the loaded library, otherwise access is restricted to the process. + * @param symbolName optional symbol name for an OS which requires the symbol's address to retrieve the path of the containing library * @return {@link NativeLibrary} instance or {@code null} if library could not be loaded. * @throws SecurityException if user is not granted access for the named library. */ @@ -238,7 +263,7 @@ public final class NativeLibrary implements DynamicLookupHelper { final String macOSXLibName, final boolean searchSystemPath, final boolean searchSystemPathFirst, - final ClassLoader loader, final boolean global) throws SecurityException { + final ClassLoader loader, final boolean global, final String symbolName) throws SecurityException { final List<String> possiblePaths = enumerateLibraryPaths(windowsLibName, unixLibName, macOSXLibName, @@ -267,7 +292,7 @@ public final class NativeLibrary implements DynamicLookupHelper { res = 0; } if ( 0 != res ) { - return new NativeLibrary(dynLink, res, path, global); + return new NativeLibrary(dynLink, res, path, global, symbolName); } else if( DEBUG ) { if( null != t ) { System.err.println("NativeLibrary.open: Caught "+t.getClass().getSimpleName()+": "+t.getMessage()); @@ -366,6 +391,11 @@ public final class NativeLibrary implements DynamicLookupHelper { return libraryPath; } + /** Returns the native library path of the opened native {@link #getLibraryHandle()}, maybe null if not supported by OS. */ + public final String getNativeLibraryPath() { + return nativeLibraryPath; + } + /** Closes this native library. Further lookup operations are not allowed after calling this method. * @throws SecurityException if user is not granted access for the named library. |