[Asterisk-Dev] loader issues.
Luigi Rizzo
rizzo at icir.org
Thu May 19 08:46:27 MST 2005
I think there are two issues in the current loading scheme.
First is a namespace pollution - by forcing each module
have global symbols with 'common' names such as key, usecount,
reload, description we cannot easily run with, say, -Wshadow
or other stricter compiler checks.
Putting all callbacks in a single descriptor would ease life
to the compiler and the developer by reducing the namespace
pollution.
Secondly, in loader.c i notice the following comment:
/* Resource modules are always loaded global and lazy */
flags = (RTLD_GLOBAL | RTLD_LAZY);
I understand that in this way you can do dirty things such as
allowing module A to use module B's symbols and vice-versa,
but this makes really really easy to shoot yourself in the foot
at runtime.
In fact, both things seem to me dangerous for two reasons:
1) by using RTLD_LAZY, you defer symbol resolution at a later time,
which is probably the opposite of what you want -- surely
you want to know of unresolved symbols at the time you load a
module and not much later perhaps in the middle of some unrelated
action;
2) RTLD_GLOBAL opens the door to unwanted bugs, e.g. a module defining
global symbols by mistake, and making them available to others in
unwanted ways.
How about providing a controlled mechanism through which a module
can export symbols in a controlled way, so that other modules that
need them also have to signal its use through a usecount call.
E.g. something like
struc exported_symbols {
const char *name;
void *value;
}
struct module_desc {
int (*load_module)(void);
int (*unload_module)(void);
int (*usecount)(void);
const char *description;
const char *key;
struc exported_symbols *s;
}
and in a module, say res/res_monitor.c, which exports ast_monitor_start
static struct exported_symbols ee[] = {
{ "ast_monitor_start", ast_monitor_start},
{ NULL, NULL }
}
struct module_desc module_desc = {
.reload = NULL, /* XXX missing ? */
.load_module = monitor_load_module,
.unload_module = monitor_unload_module,
.description = "Call Monitoring Resource",
.key = ASTERISK_GPL_KEY,
.usecount = my_usecount,
.s = ee
}
now a trivial loader function could be used to do a lookup of
the desired symbol by name, and increment the usecount of the
corresponding module. Way way safer than what we have now.
void *sym_lookup(const char *sym)
{
struct module *m;
struct exported_symbols *e;
/* lock modlock */
for (m = module_list; m ; m = m->next)
for (e = m->s; e && e->name; e++)
if (!strcmp(e->name, sym) {
/* update m->usecount */
/* unlock modlock */
return e->value;
}
/* not found */
/* unlock modlock */
return NULL;
}
Users then would do
if (ast_monitor_start == NULL)
ast_monitor_start = sym_lookup("ast_monitor_start")
if (ast_monitor_start == NULL) {
ast_log(" ... sorry... would you like to panic instead ?");
else
ast_monitor_start( ... );
I understand that dereferencing the pointer the first time
has some overhead (you need to do a lookup), but in the
current state of affairs you risk a panic, which is not nice either.
cheers
luigi
More information about the asterisk-dev
mailing list