In r214728, if dlopen() is called for the object that has been already

loaded as a dependency and marked -z nodlopen, object' DAG is already
initialized by load_needed_objects(). Due to this, the init_dag() call
from dlopen() does not increment refcount for the object [1].

Change init_dag() to not increment DAG refcount. Require explicit calls
to ref_dag() to increment, and assert that ref_dag() and unref_dag()
are called for root that has dag initialized. To fix the noted issue,
unconditionally call both init_dag() and ref_dag() in dlopen() for the
case when the object was already loaded, making it similar to the case
of newly loaded object.

Noted by:	jh [1]
Reviewed by:	jh, kan
MFC after:	6 days
This commit is contained in:
Konstantin Belousov 2010-11-04 09:29:00 +00:00
parent 5dc7bbafc8
commit 4495a80b97

View File

@ -1290,7 +1290,6 @@ init_dag1(Obj_Entry *root, Obj_Entry *obj, DoneList *dlp)
if (donelist_check(dlp, obj))
return;
obj->refcount++;
objlist_push_tail(&obj->dldags, root);
objlist_push_tail(&root->dagmembers, obj);
for (needed = obj->needed; needed != NULL; needed = needed->next)
@ -2031,6 +2030,7 @@ dlopen(const char *name, int mode)
assert(*old_obj_tail == obj);
result = load_needed_objects(obj, RTLD_LO_DLOPEN);
init_dag(obj);
ref_dag(obj);
if (result != -1)
result = rtld_verify_versions(&obj->dagmembers);
if (result != -1 && ld_tracing)
@ -2054,10 +2054,8 @@ dlopen(const char *name, int mode)
* already loaded as a dependency, initialize the dag
* starting at it.
*/
if (obj->dl_refcount == 1)
init_dag(obj);
else
ref_dag(obj);
init_dag(obj);
ref_dag(obj);
if (ld_tracing)
goto trace;
@ -3085,6 +3083,7 @@ ref_dag(Obj_Entry *root)
{
Objlist_Entry *elm;
assert(root->dag_inited);
STAILQ_FOREACH(elm, &root->dagmembers, link)
elm->obj->refcount++;
}
@ -3094,6 +3093,7 @@ unref_dag(Obj_Entry *root)
{
Objlist_Entry *elm;
assert(root->dag_inited);
STAILQ_FOREACH(elm, &root->dagmembers, link)
elm->obj->refcount--;
}