From 7e3cf7d438c8a1392812639d119a12280d8dd85c Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Wed, 7 Feb 2024 18:04:58 +0900 Subject: [PATCH] [Helper] PluginManager: Check symbol (real) location and avoid calling wrong entrypoint (Mac/Linux) (#4466) * add test on a second plugin with a dependency on an other plugin * fix runsofa test * Unix: check the loaded symbol location is correct (from the specified lib) * track error message while loading symbols * fix missing include for mac * more informative message --- .../src/sofa/helper/system/DynamicLibrary.cpp | 42 +++++++++++++++++++ .../src/sofa/helper/system/PluginManager.cpp | 18 ++++---- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/Sofa/framework/Helper/src/sofa/helper/system/DynamicLibrary.cpp b/Sofa/framework/Helper/src/sofa/helper/system/DynamicLibrary.cpp index 8c5e3b36030..b5a30eeaacb 100644 --- a/Sofa/framework/Helper/src/sofa/helper/system/DynamicLibrary.cpp +++ b/Sofa/framework/Helper/src/sofa/helper/system/DynamicLibrary.cpp @@ -28,6 +28,8 @@ using sofa::helper::system::FileSystem; # include #endif #include +#include +#include namespace sofa::helper::system { @@ -109,6 +111,46 @@ void * DynamicLibrary::getSymbolAddress(Handle handle, # endif if(symbolAddress == nullptr) fetchLastError(); +#if not defined (WIN32) + else // checking that the symbol really comes from the provided library + { + constexpr auto getRealPath = [] (const auto& strpath) + { + std::filesystem::path path(strpath); + if(std::filesystem::is_symlink(path)) + { + auto symlinkHandlePath = std::filesystem::read_symlink(path); + // symlink created by the build process are relative + if(symlinkHandlePath.is_relative()) + { + path = path.parent_path() / symlinkHandlePath; + } + } + return path; + }; + + Dl_info dli; + ::dladdr(symbolAddress, &dli); + std::filesystem::path dlInfoPath = getRealPath(dli.dli_fname); + + std::filesystem::path handlePath = getRealPath(handle.filename()); + + // Both paths should be exactly the same + if(dlInfoPath.compare(handlePath) != 0) + { + std::ostringstream oss; + oss << symbol << " was found in the library " << dlInfoPath + << " , but it should have been found in this library " << handlePath << "\n." + << "The most probable reason is that your requested library " << handlePath.filename() + << " does not implement the symbol " << symbol << ", but its dependency " + << dlInfoPath.filename()<< " does."; + + // the symbol was found in an other library (dependency) + symbolAddress = nullptr; + m_lastError = oss.str(); + } + } +#endif return symbolAddress; } diff --git a/Sofa/framework/Helper/src/sofa/helper/system/PluginManager.cpp b/Sofa/framework/Helper/src/sofa/helper/system/PluginManager.cpp index 4a5a4be7746..fd7ae46015e 100644 --- a/Sofa/framework/Helper/src/sofa/helper/system/PluginManager.cpp +++ b/Sofa/framework/Helper/src/sofa/helper/system/PluginManager.cpp @@ -31,7 +31,7 @@ using sofa::helper::system::FileSystem; #include namespace fs = std::filesystem; #elif __has_include() - #include + #include namespace fs = std::experimental::filesystem; #else error "Missing the header." @@ -49,7 +49,7 @@ namespace { template -bool getPluginEntry(LibraryEntry& entry, DynamicLibrary::Handle handle) +[[nodiscard]] bool getPluginEntry(LibraryEntry& entry, DynamicLibrary::Handle handle) { typedef typename LibraryEntry::FuncPtr FuncPtr; entry.func = (FuncPtr)DynamicLibrary::getSymbolAddress(handle, entry.symbol); @@ -199,17 +199,21 @@ PluginManager::PluginLoadStatus PluginManager::loadPluginByPath(const std::strin if (errlog) (*errlog) << msg << std::endl; return PluginLoadStatus::MISSING_SYMBOL; } - getPluginEntry(p.getModuleName,d); + + if(!getPluginEntry(p.getModuleName,d)) + { + dmsg_warning("PluginManager") << DynamicLibrary::getLastError(); + } if (checkDuplicatedPlugin(p, pluginPath)) { return PluginLoadStatus::ALREADY_LOADED; } - getPluginEntry(p.getModuleDescription,d); - getPluginEntry(p.getModuleLicense,d); - getPluginEntry(p.getModuleComponentList,d); - getPluginEntry(p.getModuleVersion,d); + [[maybe_unused]] const auto moduleDescriptionResult = getPluginEntry(p.getModuleDescription,d); + [[maybe_unused]] const auto moduleLicenseResult = getPluginEntry(p.getModuleLicense,d); + [[maybe_unused]] const auto moduleComponentListResult = getPluginEntry(p.getModuleComponentList,d); + [[maybe_unused]] const auto moduleVersionResult = getPluginEntry(p.getModuleVersion,d); } p.dynamicLibrary = d;