Blob Blame History Raw
From 8ab0393b42e08655a5fee0a8e84b3ba84932465b Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Fri, 24 May 2019 20:31:24 +0200
Subject: [PATCH 18/25] rawmidi: use snd_dlobj_cache_get2() in rawmidi open
 (coverity)

Use proper reference counting for the dynamic symbol.

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 include/local.h             |  3 +++
 src/dlmisc.c                | 41 ++++++++++++++++++++++++++++++++++-------
 src/rawmidi/rawmidi.c       | 43 +++++++++++++++++++------------------------
 src/rawmidi/rawmidi_local.h |  2 +-
 4 files changed, 57 insertions(+), 32 deletions(-)

diff --git a/include/local.h b/include/local.h
index 5edad317e955..e8390df59994 100644
--- a/include/local.h
+++ b/include/local.h
@@ -328,6 +328,8 @@ static inline int snd_open_device(const char *filename, int fmode)
 /* make local functions really local */
 #define snd_dlobj_cache_get \
 	snd1_dlobj_cache_get
+#define snd_dlobj_cache_get2 \
+	snd1_dlobj_cache_get2
 #define snd_dlobj_cache_put \
 	snd1_dlobj_cache_put
 #define snd_dlobj_cache_cleanup \
@@ -341,6 +343,7 @@ static inline int snd_open_device(const char *filename, int fmode)
 
 /* dlobj cache */
 void *snd_dlobj_cache_get(const char *lib, const char *name, const char *version, int verbose);
+void *snd_dlobj_cache_get2(const char *lib, const char *name, const char *version, int verbose);
 int snd_dlobj_cache_put(void *open_func);
 void snd_dlobj_cache_cleanup(void);
 
diff --git a/src/dlmisc.c b/src/dlmisc.c
index 012e61bc00c0..8c8f3ff72fd3 100644
--- a/src/dlmisc.c
+++ b/src/dlmisc.c
@@ -251,15 +251,15 @@ static inline void snd_dlobj_unlock(void) {}
 
 static LIST_HEAD(pcm_dlobj_list);
 
-void *snd_dlobj_cache_get(const char *lib, const char *name,
-			  const char *version, int verbose)
+static struct dlobj_cache *
+snd_dlobj_cache_get0(const char *lib, const char *name,
+		     const char *version, int verbose)
 {
 	struct list_head *p;
 	struct dlobj_cache *c;
 	void *func, *dlobj;
 	char errbuf[256];
 
-	snd_dlobj_lock();
 	list_for_each(p, &pcm_dlobj_list) {
 		c = list_entry(p, struct dlobj_cache, list);
 		if (c->lib && lib && strcmp(c->lib, lib) != 0)
@@ -270,9 +270,7 @@ void *snd_dlobj_cache_get(const char *lib, const char *name,
 			continue;
 		if (strcmp(c->name, name) == 0) {
 			c->refcnt++;
-			func = c->func;
-			snd_dlobj_unlock();
-			return func;
+			return c;
 		}
 	}
 
@@ -285,7 +283,6 @@ void *snd_dlobj_cache_get(const char *lib, const char *name,
 			SNDERR("Cannot open shared library %s (%s)",
 						lib ? lib : "[builtin]",
 						errbuf);
-		snd_dlobj_unlock();
 		return NULL;
 	}
 
@@ -314,6 +311,36 @@ void *snd_dlobj_cache_get(const char *lib, const char *name,
 	c->dlobj = dlobj;
 	c->func = func;
 	list_add_tail(&c->list, &pcm_dlobj_list);
+	return c;
+}
+
+void *snd_dlobj_cache_get(const char *lib, const char *name,
+			  const char *version, int verbose)
+{
+	struct dlobj_cache *c;
+	void *func = NULL;
+
+	snd_dlobj_lock();
+	c = snd_dlobj_cache_get0(lib, name, version, verbose);
+	if (c)
+		func = c->func;
+	snd_dlobj_unlock();
+	return func;
+}
+
+void *snd_dlobj_cache_get2(const char *lib, const char *name,
+			   const char *version, int verbose)
+{
+	struct dlobj_cache *c;
+	void *func = NULL;
+
+	snd_dlobj_lock();
+	c = snd_dlobj_cache_get0(lib, name, version, verbose);
+	if (c) {
+		func = c->func;
+		/* double reference */
+		c->refcnt++;
+	}
 	snd_dlobj_unlock();
 	return func;
 }
diff --git a/src/rawmidi/rawmidi.c b/src/rawmidi/rawmidi.c
index 2f419142b9b5..1b5f8525e59e 100644
--- a/src/rawmidi/rawmidi.c
+++ b/src/rawmidi/rawmidi.c
@@ -162,7 +162,7 @@ static int snd_rawmidi_open_conf(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp
 				 snd_config_t *rawmidi_conf, int mode)
 {
 	const char *str;
-	char buf[256], errbuf[256];
+	char buf[256];
 	int err;
 	snd_config_t *conf, *type_conf = NULL;
 	snd_config_iterator_t i, next;
@@ -174,7 +174,6 @@ static int snd_rawmidi_open_conf(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp
 #ifndef PIC
 	extern void *snd_rawmidi_open_symbols(void);
 #endif
-	void *h = NULL;
 	if (snd_config_get_type(rawmidi_conf) != SND_CONFIG_TYPE_COMPOUND) {
 		if (name)
 			SNDERR("Invalid type for RAWMIDI %s definition", name);
@@ -239,41 +238,37 @@ static int snd_rawmidi_open_conf(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp
 #ifndef PIC
 	snd_rawmidi_open_symbols();
 #endif
-	h = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf));
-	if (h)
-		open_func = snd_dlsym(h, open_name, SND_DLSYM_VERSION(SND_RAWMIDI_DLSYM_VERSION));
-	err = 0;
-	if (!h) {
-		SNDERR("Cannot open shared library %s (%s)", lib, errbuf);
-		err = -ENOENT;
-	} else if (!open_func) {
-		SNDERR("symbol %s is not defined inside %s", open_name, lib);
-		snd_dlclose(h);
+	open_func = snd_dlobj_cache_get2(lib, open_name,
+			SND_DLSYM_VERSION(SND_RAWMIDI_DLSYM_VERSION), 1);
+	if (!open_func) {
 		err = -ENXIO;
+		goto _err;
 	}
-       _err:
 	if (type_conf)
 		snd_config_delete(type_conf);
-	if (err >= 0)
-		err = open_func(inputp, outputp, name, rawmidi_root, rawmidi_conf, mode);
-	if (err < 0) {
-		if (h)
-			snd_dlclose(h);
-		return err;
-	}
+	err = open_func(inputp, outputp, name, rawmidi_root, rawmidi_conf, mode);
+	if (err < 0)
+		goto _err;
 	if (inputp) {
-		(*inputp)->dl_handle = h; h = NULL;
+		(*inputp)->open_func = open_func;
 		snd_rawmidi_params_default(*inputp, &params);
 		err = snd_rawmidi_params(*inputp, &params);
 		assert(err >= 0);
 	}
 	if (outputp) {
-		(*outputp)->dl_handle = h;
+		(*outputp)->open_func = open_func;
 		snd_rawmidi_params_default(*outputp, &params);
 		err = snd_rawmidi_params(*outputp, &params);
 		assert(err >= 0);
 	}
 	return 0;
+
+       _err:
+	if (open_func)
+		snd_dlobj_cache_put(open_func);
+	if (type_conf)
+		snd_config_delete(type_conf);
+	return err;
 }
 
 static int snd_rawmidi_open_noupdate(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
@@ -350,8 +345,8 @@ int snd_rawmidi_close(snd_rawmidi_t *rawmidi)
   	assert(rawmidi);
 	err = rawmidi->ops->close(rawmidi);
 	free(rawmidi->name);
-	if (rawmidi->dl_handle)
-		snd_dlclose(rawmidi->dl_handle);
+	if (rawmidi->open_func)
+		snd_dlobj_cache_put(rawmidi->open_func);
 	free(rawmidi);
 	return err;
 }
diff --git a/src/rawmidi/rawmidi_local.h b/src/rawmidi/rawmidi_local.h
index d76b35a33bf4..721e1ec9deec 100644
--- a/src/rawmidi/rawmidi_local.h
+++ b/src/rawmidi/rawmidi_local.h
@@ -37,7 +37,7 @@ typedef struct {
 } snd_rawmidi_ops_t;
 
 struct _snd_rawmidi {
-	void *dl_handle;
+	void *open_func;
 	char *name;
 	snd_rawmidi_type_t type;
 	snd_rawmidi_stream_t stream;
-- 
2.16.4