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 list_head *p;
 | 
				
			||||||
	struct dlobj_cache *c;
 | 
						struct dlobj_cache *c;
 | 
				
			||||||
	void *func, *dlobj = NULL;
 | 
						void *func, *dlobj;
 | 
				
			||||||
	int dlobj_close = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	snd_dlobj_lock();
 | 
						snd_dlobj_lock();
 | 
				
			||||||
	list_for_each(p, &pcm_dlobj_list) {
 | 
						list_for_each(p, &pcm_dlobj_list) {
 | 
				
			||||||
| 
						 | 
					@ -220,7 +219,6 @@ void *snd_dlobj_cache_get(const char *lib, const char *name,
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		if (!lib && c->lib)
 | 
							if (!lib && c->lib)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		dlobj = c->dlobj;
 | 
					 | 
				
			||||||
		if (strcmp(c->name, name) == 0) {
 | 
							if (strcmp(c->name, name) == 0) {
 | 
				
			||||||
			c->refcnt++;
 | 
								c->refcnt++;
 | 
				
			||||||
			func = c->func;
 | 
								func = c->func;
 | 
				
			||||||
| 
						 | 
					@ -228,17 +226,16 @@ void *snd_dlobj_cache_get(const char *lib, const char *name,
 | 
				
			||||||
			return func;
 | 
								return func;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dlobj = snd_dlopen(lib, RTLD_NOW);
 | 
				
			||||||
	if (dlobj == NULL) {
 | 
						if (dlobj == NULL) {
 | 
				
			||||||
		dlobj = snd_dlopen(lib, RTLD_NOW);
 | 
							if (verbose)
 | 
				
			||||||
		if (dlobj == NULL) {
 | 
								SNDERR("Cannot open shared library %s",
 | 
				
			||||||
			if (verbose)
 | 
					 | 
				
			||||||
				SNDERR("Cannot open shared library %s",
 | 
					 | 
				
			||||||
						lib ? lib : "[builtin]");
 | 
											lib ? lib : "[builtin]");
 | 
				
			||||||
			snd_dlobj_unlock();
 | 
							snd_dlobj_unlock();
 | 
				
			||||||
			return NULL;
 | 
							return NULL;
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		dlobj_close = 1;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	func = snd_dlsym(dlobj, name, version);
 | 
						func = snd_dlsym(dlobj, name, version);
 | 
				
			||||||
	if (func == NULL) {
 | 
						if (func == NULL) {
 | 
				
			||||||
		if (verbose)
 | 
							if (verbose)
 | 
				
			||||||
| 
						 | 
					@ -257,8 +254,7 @@ void *snd_dlobj_cache_get(const char *lib, const char *name,
 | 
				
			||||||
		free((void *)c->lib);
 | 
							free((void *)c->lib);
 | 
				
			||||||
		free(c);
 | 
							free(c);
 | 
				
			||||||
	      __err:
 | 
						      __err:
 | 
				
			||||||
		if (dlobj_close)
 | 
							snd_dlclose(dlobj);
 | 
				
			||||||
			snd_dlclose(dlobj);
 | 
					 | 
				
			||||||
		snd_dlobj_unlock();
 | 
							snd_dlobj_unlock();
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -298,16 +294,11 @@ void snd_dlobj_cache_cleanup(void)
 | 
				
			||||||
	struct list_head *p, *npos;
 | 
						struct list_head *p, *npos;
 | 
				
			||||||
	struct dlobj_cache *c;
 | 
						struct dlobj_cache *c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* clean up caches only when really no user is present */
 | 
					 | 
				
			||||||
	snd_dlobj_lock();
 | 
						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) {
 | 
						list_for_each_safe(p, npos, &pcm_dlobj_list) {
 | 
				
			||||||
		c = list_entry(p, struct dlobj_cache, list);
 | 
							c = list_entry(p, struct dlobj_cache, list);
 | 
				
			||||||
 | 
							if (c->refcnt)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
		list_del(p);
 | 
							list_del(p);
 | 
				
			||||||
		snd_dlclose(c->dlobj);
 | 
							snd_dlclose(c->dlobj);
 | 
				
			||||||
		free((void *)c->name); /* shut up gcc warning */
 | 
							free((void *)c->name); /* shut up gcc warning */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue