mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -05:00 
			
		
		
		
	Fix doubly call of dlclose() in dlobj caching code
When multiple dlobj_cache items point to the same dlobj, dlclose() may be called wrongly multiple times when these items are cleared, because we manage the dlobj_cache list as a flat list. This results in a bad segfault we've seen in openal-soft, for example. For fixing this, we need the refcounting of dlobj itself. But, in this case, we don't have to manage yet another list, since dlopen() does a proper refcounting by itself. That is, we can just call always dlopen() at each time a new function is assigned, and also call dlclose() for each released dlobj_cache item at cleanup. Bugzilla: https://bugzilla.novell.com/show_bug.cgi?id=814250 Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
		
							parent
							
								
									812e4b0c5b
								
							
						
					
					
						commit
						e1e40c2553
					
				
					 1 changed files with 11 additions and 20 deletions
				
			
		
							
								
								
									
										31
									
								
								src/dlmisc.c
									
										
									
									
									
								
							
							
						
						
									
										31
									
								
								src/dlmisc.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -208,8 +208,7 @@ void *snd_dlobj_cache_get(const char *lib, const char *name,
 | 
			
		|||
{
 | 
			
		||||
	struct list_head *p;
 | 
			
		||||
	struct dlobj_cache *c;
 | 
			
		||||
	void *func, *dlobj = NULL;
 | 
			
		||||
	int dlobj_close = 0;
 | 
			
		||||
	void *func, *dlobj;
 | 
			
		||||
 | 
			
		||||
	snd_dlobj_lock();
 | 
			
		||||
	list_for_each(p, &pcm_dlobj_list) {
 | 
			
		||||
| 
						 | 
				
			
			@ -220,7 +219,6 @@ void *snd_dlobj_cache_get(const char *lib, const char *name,
 | 
			
		|||
			continue;
 | 
			
		||||
		if (!lib && c->lib)
 | 
			
		||||
			continue;
 | 
			
		||||
		dlobj = c->dlobj;
 | 
			
		||||
		if (strcmp(c->name, name) == 0) {
 | 
			
		||||
			c->refcnt++;
 | 
			
		||||
			func = c->func;
 | 
			
		||||
| 
						 | 
				
			
			@ -228,17 +226,16 @@ void *snd_dlobj_cache_get(const char *lib, const char *name,
 | 
			
		|||
			return func;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dlobj = snd_dlopen(lib, RTLD_NOW);
 | 
			
		||||
	if (dlobj == NULL) {
 | 
			
		||||
		dlobj = snd_dlopen(lib, RTLD_NOW);
 | 
			
		||||
		if (dlobj == NULL) {
 | 
			
		||||
			if (verbose)
 | 
			
		||||
				SNDERR("Cannot open shared library %s",
 | 
			
		||||
		if (verbose)
 | 
			
		||||
			SNDERR("Cannot open shared library %s",
 | 
			
		||||
						lib ? lib : "[builtin]");
 | 
			
		||||
			snd_dlobj_unlock();
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
		dlobj_close = 1;
 | 
			
		||||
		snd_dlobj_unlock();
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	func = snd_dlsym(dlobj, name, version);
 | 
			
		||||
	if (func == NULL) {
 | 
			
		||||
		if (verbose)
 | 
			
		||||
| 
						 | 
				
			
			@ -257,8 +254,7 @@ void *snd_dlobj_cache_get(const char *lib, const char *name,
 | 
			
		|||
		free((void *)c->lib);
 | 
			
		||||
		free(c);
 | 
			
		||||
	      __err:
 | 
			
		||||
		if (dlobj_close)
 | 
			
		||||
			snd_dlclose(dlobj);
 | 
			
		||||
		snd_dlclose(dlobj);
 | 
			
		||||
		snd_dlobj_unlock();
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -298,16 +294,11 @@ void snd_dlobj_cache_cleanup(void)
 | 
			
		|||
	struct list_head *p, *npos;
 | 
			
		||||
	struct dlobj_cache *c;
 | 
			
		||||
 | 
			
		||||
	/* clean up caches only when really no user is present */
 | 
			
		||||
	snd_dlobj_lock();
 | 
			
		||||
	list_for_each(p, &pcm_dlobj_list) {
 | 
			
		||||
		c = list_entry(p, struct dlobj_cache, list);
 | 
			
		||||
		if (c->refcnt)
 | 
			
		||||
			goto unlock;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_for_each_safe(p, npos, &pcm_dlobj_list) {
 | 
			
		||||
		c = list_entry(p, struct dlobj_cache, list);
 | 
			
		||||
		if (c->refcnt)
 | 
			
		||||
			continue;
 | 
			
		||||
		list_del(p);
 | 
			
		||||
		snd_dlclose(c->dlobj);
 | 
			
		||||
		free((void *)c->name); /* shut up gcc warning */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue