[Bug 246462] dlopen incorrect resolution of symbols [RTLD_DEEPBIND]
bugzilla-noreply at freebsd.org
bugzilla-noreply at freebsd.org
Thu May 14 08:14:57 UTC 2020
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=246462
Bug ID: 246462
Summary: dlopen incorrect resolution of symbols [RTLD_DEEPBIND]
Product: Base System
Version: 12.1-RELEASE
Hardware: Any
OS: Any
Status: New
Severity: Affects Only Me
Priority: ---
Component: bin
Assignee: bugs at FreeBSD.org
Reporter: d8zNeCFG at aon.at
Introduction: This issue arose in the context of trying to upgrade a port
(databases/postgresql-mysql_fdw) but is actually about the behavior of
rtld/dlopen which seems to have changed (probably with the switch to
clang/llvm).
Scenario:
- System running FreeBSD 12.1-RELEASE-p4 #4 r360692M
- Ports at latest, mysql57-server and postgresql12-server installed
- Trying to upgrade databases/postgresql-mysql_fdw from its current 2.5.1 to
2.5.3
Note: databases/postgresql-mysql_fdw is a foreign data wrapper which enables a
Postgres server to access remote MySQL databases.
Scenario (continued):
- The upgrade is straightforward, just adapt the Makefile and distinfo, and it
compiles and can be installed.
- After installation, the local database is extended to be able to access the
remote MySQL database using
CREATE EXTENSION mysql_fdw;
CREATE_SERVER ...
CREATE USER MAPPING ...
GRANT USAGE ON FOREIGN SERVER ...
CREATE SCHEMA ...
IMPORT FOREIGN SCHEMA ...
- Then a foreign table is accessed using SELECT * FROM <foreign table>;
Result:
- When accessing the foreign table, the first access retrieves a correct
result, and then the postgres process handling the postgres database client
crashes with segmentation violation (signal 11), producing a core file.
Scenario (continued):
- Debugging the core file using lldb -c /tmp/postgres.core
/usr/local/bin/postgres
Result:
(lldb) thread backtrace
* thread #1, name = 'postgres', stop reason = signal SIGSEGV
* frame #0: 0x00000000009002eb postgres`pfree + 11
frame #1: 0x00000000006a50de postgres`list_delete + 206
frame #2: 0x000000080b4f7d36 libmysqlclient.so`mysql_stmt_close + 102
Explanation: I believe what is happening here is that mysql_stmt_close calls
list_delete, but this list_delete gets resolved to the version in the postgres
binary instead of the function of the same name in libmysqlclient.so. This is
because MySQL and Postgres are using the same names for different functions of
their own, and in this case the wrong one is being called.
A while ago, when the databases/postgresql-mysql_fdw port was last upgraded
some years ago, this seemingly was not the case. Specifically, in the source
code of this port one finds the following comment:
/*
* mysql_load_library function dynamically load the mysql's library
* libmysqlclient.so. The only reason to load the library using dlopen
* is that, mysql and postgres both have function with same name like
* "list_delete", "list_delete" and "list_free" which cause compiler
* error "duplicate function name" and erroneously linking with a function.
* This port of the code is used to avoid the compiler error.
*
* #define list_delete mysql_list_delete
* #include <mysql.h>
* #undef list_delete
*
* But system crashed on function mysql_stmt_close function because
* mysql_stmt_close internally calling "list_delete" function which
* wrongly binds to postgres' "list_delete" function.
*
* The dlopen function provides a parameter "RTLD_DEEPBIND" which
* solved the binding issue.
*
* RTLD_DEEPBIND:
* Place the lookup scope of the symbols in this library ahead of the
* global scope. This means that a self-contained library will use its
* own symbols in preference to global symbols with the same name contained
* in libraries that have already been loaded.
*/
bool
mysql_load_library(void)
{
#if defined(__APPLE__) || defined(__FreeBSD__)
/*
* Mac OS/BSD does not support RTLD_DEEPBIND, but it still
* works without the RTLD_DEEPBIND
*/
mysql_dll_handle = dlopen(_MYSQL_LIBNAME, RTLD_LAZY);
#else
mysql_dll_handle = dlopen(_MYSQL_LIBNAME, RTLD_LAZY | RTLD_DEEPBIND);
#endif
if(mysql_dll_handle == NULL)
return false;
Conclusion: It seems that the behavior of the runtime loader changed such that
now the executable's symbols are searched before a library's symbols when
resolving references arising from that library (in this case,
libmysqlclient.so). It further seems that there are two possible resolutions:
Either re-introduce the old behavior (which made it unnecessary to use
RTLD_DEEPBIND in FreeBSD), or implement RTLD_DEEPBIND for FreeBSD.
-- Martin
--
You are receiving this mail because:
You are the assignee for the bug.
More information about the freebsd-bugs
mailing list