[ZBXNEXT-3388] Load libraries in runtime with RTLD_LOCAL flag Created: 2016 Aug 19  Updated: 2019 Apr 10

Status: Open
Project: ZABBIX FEATURE REQUESTS
Component/s: Agent (G), Proxy (P), Server (S)
Affects Version/s: 3.2.0alpha2
Fix Version/s: None

Type: Change Request Priority: Major
Reporter: Glebs Ivanovskis (Inactive) Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: crash, dependencies
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Duplicate
is duplicated by ZBX-15964 ODBC item causes Zabbix Server to crash Closed
Sub-task
depends on ZBX-12159 Resolving TNS names via LDAP crash on... Confirmed
part of ZBX-13239 ODBC crashes zabbix_server Closed

 Description   

Let's start with a small demonstration. Let's build a small application (test) linked against two libraries (liba.so and libe.so) depending on one and the same symbol (foo) from two different libraries (libb.so and libd.so).

a.c:

#include "a.h"
#include "b.h"

void	a_foo(void)
{
	foo();
}

a.h:

void	a_foo(void);

b.c:

#include <stdio.h>

void	foo(void)
{
	printf("bar\n");
}

b.h:

void foo(void);

d.c:

#include <stdio.h>

void	foo(void)
{
	printf("baz\n");
}

d.h:

void	foo(void);

e.c:

#include "d.h"
#include "e.h"

void	e_foo(void)
{
	foo();
}

e.h:

void	e_foo(void);

Let's build libraries:

$ gcc -o libb.so b.c -fPIC -shared
$ gcc -o libd.so d.c -fPIC -shared
$ gcc -o liba.so a.c -lb -L. -fPIC -shared
$ gcc -o libe.so e.c -ld -L. -fPIC -shared

Let's first test them separately.
test_a:

#include "a.h"

int	main(void)
{
	a_foo();

	return 0;
}

test_e.c:

#include "e.h"

int	main(void)
{
	e_foo();

	return 0;
}
$ export LD_LIBRARY_PATH=.
$ gcc -o test_a test_a.c -la -L.
$ gcc -o test_e test_e.c -le -L.
$ ./test_a
bar
$ ./test_e
baz

So far everything is as expected. Now let's link both libraries to the same program.
test_both.c:

#include "a.h"
#include "e.h"

int	main(void)
{
	a_foo();
	e_foo();

	return 0;
}

Both a_foo() and e_foo() print "bar" or "baz" depending on -l flag order:

$ gcc -o test_both test_both.c -la -le -L.
$ ./test_both
bar
bar
$ gcc -o test_both test_both.c -le -la -L.
$ ./test_both
baz
baz

If program has it's own symbol foo it gets even better.
test_own.c:

#include "a.h"
#include "e.h"
#include <stdio.h>

void	foo(void)
{
	printf("foo\n");
}

int	main(void)
{
	a_foo();
	e_foo();

	return 0;
}

Symbol foo from liba.so and libe.so gets resolved to the foo exported by the program itself:

$ gcc -o test_own test_own.c -la -le -L.
$ ./test_own
foo
foo

But with a different approach it is possible to sort it out.
test_rtld.c:

#include <stdio.h>
#include <dlfcn.h>

void	foo(void)
{
	printf("foo\n");
}

int	main(void)
{
	void	*liba, *libe;
	void	(*a_foo)(void);
	void	(*e_foo)(void);

	liba = dlopen("liba.so", RTLD_NOW | RTLD_LOCAL);
	libe = dlopen("libe.so", RTLD_NOW | RTLD_LOCAL);

	a_foo = dlsym(liba, "foo");
	e_foo = dlsym(libe, "foo");

	foo();
	a_foo();
	e_foo();

	dlclose(liba);
	dlclose(libe);

	return 0;
}
$ gcc -o test_rtld test_rtld.c -ldl
$ ./test_rtld 
foo
bar
baz

Most important question: How is it related to Zabbix?

Zabbix depends on a number of libraries (cURL, Net-SNMP, OpenIPMI, DB client libraries, ...) which all require encryption libraries as a secondary dependency. Zabbix uses DB client libraries to access its database and links against UnixODBC which loads ODBC drivers which require DB client libraries too. Sometimes they all need different versions of the same library and inability to resolve symbols correctly (slight difference between "bar" and "baz" in the example above) often leads to crashes.



 Comments   
Comment by Glebs Ivanovskis (Inactive) [ 2016 Aug 19 ]

List of potentially related tickets: ZBX-8005, ZBX-9035, ZBX-10461, ZBX-10656, ZBX-10897, ZBX-11017, ZBX-12159.

Generated at Sat Apr 20 16:54:25 EEST 2024 using Jira 9.12.4#9120004-sha1:625303b708afdb767e17cb2838290c41888e9ff0.