Bug#435146: asterisk-h323: Asterisk crashes on startup with H323 package installed.

Faidon Liambotis paravoid at debian.org
Mon Aug 20 00:48:29 UTC 2007


clone 435146 -1
reassign -1 libopenh323-1.18.0 1.18.0.dfsg-1
retitle -1 Segfault when dlclose()ing libopenh323
tags -1 -pending
thanks

I've investigating this for hours and I've concluded to this:

It seems that Asterisk's dynamic loader loads modules in two passes;
modules with global symbols are loaded in the first pass while the rest
of the modules (which can use these global symbols, hence the need for
two passes) are loaded in the second.
The information of whether a module contains global symbols or not is
stored inside the module as a flag.
Hence, the dynamic loader dlopen()s libraries with RTLD_LAZY |
RTLD_LOCAL, checks the flags and:
* if it is flagged global, it continues by promoting it to RTLD_GLOBAL,
* if it is not, it calls dlclose(), pending loading in the second pass.

chan_h323 is one of those that are not flagged that way; hence it is
dlopen()ed/dlclose()d in the first pass and dlopen()ed another time in
the second.

Of course, when dlopening a shared library, all of its dependencies
(e.g. libopenh323, libpt, libSDL etc. for chan_h323.so) are dynamically
loaded too and on dlclose() they are also closed.

It seems that Asterisk segfaults on the dlclose() of chan_h323.so which
in turn is caused by unloading libopenh323.

I wrote a very simple test suite that proves this and tested it with
both 1.18 and 1.19[1]. Unfortunately the backtrace, as shown earlier in
the bug report, is quite cryptic and C++ is not my area of expertise.
It is worth noting however, that if RTLD_NOW is used instead of
RTLD_LAZY (or the environment has LD_BIND_NOW, these two are equivalent)
the bug does not occur.

This is definitely a libopenh323 bug and Asterisk workarounds it by
linking the main asterisk binary against libopenh323 and hence avoiding
unloading it when its loader dlclose()s chan_h323.so.

Regards,
Faidon

[1]:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

int main(int argc, char **argv)
{
	void *handle;
	char *error;
	char *library;

	if (argc < 2) {
		fprintf(stderr, "Usage: %s foo.so\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	library = argv[1];

	handle = dlopen(library, RTLD_LAZY | RTLD_LOCAL);
	if (!handle) {
		fprintf(stderr, "%s\n", dlerror());
		exit(EXIT_FAILURE);
	}

	dlerror();	/* Clear any existing error */

	printf("loaded '%s', trying to unload...\n", library);

	/* unload dynamic library */
	dlclose(handle);
	if ((error = dlerror()) != NULL)  {
		fprintf(stderr, "%s\n", error);
		exit(EXIT_FAILURE);
	}
	printf("unloaded '%s', exiting...\n", library);

	exit(EXIT_SUCCESS);
}




More information about the Pkg-voip-maintainers mailing list