Skip to content

Commit af9cdf2

Browse files
committed
Core: replace RTLD_DEEPBIND (dlopen flag) with a new plugin flag
Using RTLD_DEEPBIND flag when loading plugin helps to solve issue with some 3rd party libraries (e.g. librdkafka) if the library redefines a common symbol. However, using this dlopen flag globally for all plugins caused segfault when using C++ iostream (e.g. "std::cout << "some text";) Plugins can use IPX_PF_DEEPBIND flag in ipx_plugin_info to instruct the collector to use RTLD_DEEPBIND when loading the plugin.
1 parent 05add4c commit af9cdf2

File tree

4 files changed

+65
-9
lines changed

4 files changed

+65
-9
lines changed

include/ipfixcol2/plugins.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,21 @@ typedef struct ipx_ctx_ext ipx_ctx_ext_t;
135135
*/
136136
#define IPX_PT_OUTPUT 3U
137137

138+
/**
139+
* \def IPX_PF_DEEPBIND
140+
* \brief Use deep bind when resolving symbols of a plugin (and additional depending libraries)
141+
*
142+
* Some plugins might depend on an external library which redefines one or more common symbols
143+
* (e.g. thrd_create) used by the collector (or other plugins). Since common version of these
144+
* symbols is resolved before any plugin is loaded, these redefined symbols are ignored.
145+
* Therefore, the plugin (or third party libraries) might not be able to correctly work.
146+
*
147+
* This flag instructs the collector to use RTLD_DEEPBIND (see manual page of dlopen) which
148+
* solves this issue. However, it might not be supported by non-glibc implementations
149+
* (as it is a GNU extension) and might break some other functions. Use only if really required!
150+
*/
151+
#define IPX_PF_DEEPBIND 1U
152+
138153
/**
139154
* \brief Identification of a plugin
140155
*
@@ -149,7 +164,7 @@ struct ipx_plugin_info {
149164
const char *dsc;
150165
/** Plugin type (one of #IPX_PT_INPUT, #IPX_PT_INTERMEDIATE, #IPX_PT_OUTPUT) */
151166
uint16_t type;
152-
/** Configuration flags (reserved for future use) */
167+
/** Configuration flags (zero or more IPX_PF_* values might be ORed here) */
153168
uint16_t flags;
154169
/** Plugin version string (like "1.2.3") */
155170
const char *version;

src/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ if (POLICY CMP0063)
22
cmake_policy(SET CMP0063 NEW)
33
endif()
44

5+
include(CheckSymbolExists)
6+
check_symbol_exists("RTLD_DEEPBIND" "dlfcn.h" HAVE_RTLD_DEEPBIND)
7+
58
# Configure a header file to pass some CMake variables
69
configure_file(
710
"${PROJECT_SOURCE_DIR}/src/build_config.h.in"

src/build_config.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@
125125
#define IPX_BUILD_ARCH "unknown"
126126
#endif
127127

128+
// Deep bind support
129+
#cmakedefine HAVE_RTLD_DEEPBIND
130+
128131
/**@}*/
129132

130133
#endif /* _BUILD_CONFIG_ */

src/core/configurator/plugin_mgr.cpp

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ ipx_plugin_mgr::cache_add_file(const char *path)
207207
dlerror();
208208

209209
// Try to load the plugin (and unload it automatically)
210-
const int flags = RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND;
210+
const int flags = RTLD_LAZY | RTLD_LOCAL;
211211
auto delete_fn = [](void *handle) {dlclose(handle);};
212212
std::unique_ptr<void, std::function<void(void*)>> handle(dlopen(path, flags), delete_fn);
213213
if (!handle) {
@@ -308,7 +308,7 @@ ipx_plugin_mgr::plugin_list()
308308
dlerror();
309309

310310
const char *path = cache_entry.path.c_str();
311-
const int flags = RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND;
311+
const int flags = RTLD_LAZY | RTLD_LOCAL;
312312
auto delete_fn = [](void *handle) {dlclose(handle);};
313313

314314
std::unique_ptr<void, std::function<void(void*)>> handle(dlopen(path, flags), delete_fn);
@@ -348,6 +348,15 @@ ipx_plugin_mgr::plugin_list()
348348
continue;
349349
}
350350

351+
if (info->flags & IPX_PF_DEEPBIND) {
352+
#ifdef HAVE_RTLD_DEEPBIND
353+
plugin_entry.msg_notes.emplace_back("Deep bind (RTLD_DEEPBIND) required");
354+
#else
355+
plugin_entry.msg_warning.emplace_back(
356+
"Deep bind (RTLD_DEEPBIND) required but not supported by C library");
357+
#endif
358+
}
359+
351360
if (!version_ok) {
352361
std::stringstream ss;
353362
ss << "incompatible with this collector version (min. required: ";
@@ -503,18 +512,44 @@ ipx_plugin_mgr::version_check(const std::string &min_version)
503512
* \param[in] path Path to the plugin to load
504513
* \param[in] auto_unload Automatically unload the plugin on destroy (can be changed later)
505514
*/
506-
ipx_plugin_mgr::plugin::plugin(const std::string &path, bool auto_unload)
515+
ipx_plugin_mgr::plugin::plugin(const std::string &path, bool auto_unload)
507516
: unload(auto_unload)
508517
{
518+
auto delete_fn = [](void *handle) {dlclose(handle);};
519+
std::unique_ptr<void, std::function<void(void*)>> handle_wrap(nullptr, delete_fn);
520+
521+
const struct ipx_plugin_info *info;
522+
int load_flags = RTLD_NOW | RTLD_LOCAL;
523+
509524
// Initialize default parameters
510525
ref_cnt = 0;
511526
std::memset(&cbs, 0, sizeof(cbs));
512527

513-
// Load the plugin
514-
auto delete_fn = [](void *handle) {dlclose(handle);};
515-
int flags = RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND;
516-
dlerror(); // Clear all errors first
517-
std::unique_ptr<void, std::function<void(void*)>> handle_wrap(dlopen(path.c_str(), flags), delete_fn);
528+
// Determine whether or not to use deep bind
529+
dlerror();
530+
handle_wrap.reset(dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL));
531+
if (!handle_wrap) {
532+
// Failed to open the file
533+
std::string err_msg = "Failed to load a plugin from '" + path + "': " + dlerror();
534+
throw ipx_plugin_mgr::error(err_msg);
535+
}
536+
537+
*(void **)(&info) = symbol_get(handle_wrap.get(), "ipx_plugin_info", false);
538+
if (info->flags & IPX_PF_DEEPBIND) {
539+
#ifdef HAVE_RTLD_DEEPBIND
540+
IPX_DEBUG(comp_str, "Loading plugin from '%s' using RTLD_DEEPBIND flag!", path.c_str());
541+
load_flags |= RTLD_DEEPBIND;
542+
#else
543+
std::string err_msg = "Deep bind (RTLD_DEEPBIND) required but not supported by C library";
544+
throw ipx_plugin_mgr::error("Failed to load a plugin from '" + path + "': " + err_msg);
545+
#endif
546+
}
547+
548+
// Close the plugin and reload it
549+
handle_wrap.reset();
550+
551+
dlerror();
552+
handle_wrap.reset(dlopen(path.c_str(), load_flags));
518553
if (!handle_wrap) {
519554
// Failed to open the file
520555
std::string err_msg = "Failed to load a plugin from '" + path + "': " + dlerror();

0 commit comments

Comments
 (0)