Fix locking issues with channel datastores in func_odbc.c.
authorRichard Mudgett <rmudgett@digium.com>
Tue, 24 Jan 2012 17:04:20 +0000 (17:04 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Tue, 24 Jan 2012 17:04:20 +0000 (17:04 +0000)
* Fixed a potential memory leak when an existing datastore is manually
destroyed by inline code instead of calling ast_datastore_free().

(closes issue ASTERISK-17948)
Reported by: Archie Cobbs

Review: https://reviewboard.asterisk.org/r/1687/
........

Merged revisions 352291 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 352292 from http://svn.asterisk.org/svn/asterisk/branches/10

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@352293 65c4cc65-6c06-0410-ace0-fbb531ad65f3

funcs/func_odbc.c

index eeb7d3b..edb69f0 100644 (file)
@@ -727,8 +727,7 @@ end_acf_read:
                                ast_channel_lock(chan);
                                if ((odbc_store = ast_channel_datastore_find(chan, &odbc_info, buf))) {
                                        ast_channel_datastore_remove(chan, odbc_store);
-                                       odbc_datastore_free(odbc_store->data);
-                                       ast_free(odbc_store);
+                                       ast_datastore_free(odbc_store);
                                }
                                ast_channel_unlock(chan);
                        }
@@ -745,7 +744,9 @@ end_acf_read:
                                return -1;
                        }
                        odbc_store->data = resultset;
+                       ast_channel_lock(chan);
                        ast_channel_datastore_add(chan, odbc_store);
+                       ast_channel_unlock(chan);
                }
        }
        SQLCloseCursor(stmt);
@@ -791,8 +792,11 @@ static int acf_fetch(struct ast_channel *chan, const char *cmd, char *data, char
        struct ast_datastore *store;
        struct odbc_datastore *resultset;
        struct odbc_datastore_row *row;
+
+       ast_channel_lock(chan);
        store = ast_channel_datastore_find(chan, &odbc_info, data);
        if (!store) {
+               ast_channel_unlock(chan);
                pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
                return -1;
        }
@@ -804,10 +808,12 @@ static int acf_fetch(struct ast_channel *chan, const char *cmd, char *data, char
                /* Cleanup datastore */
                ast_channel_datastore_remove(chan, store);
                ast_datastore_free(store);
+               ast_channel_unlock(chan);
                pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE");
                return -1;
        }
        pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", resultset->names);
+       ast_channel_unlock(chan);
        ast_copy_string(buf, row->data, len);
        ast_free(row);
        pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "SUCCESS");
@@ -824,11 +830,15 @@ static char *app_odbcfinish = "ODBCFinish";
 
 static int exec_odbcfinish(struct ast_channel *chan, const char *data)
 {
-       struct ast_datastore *store = ast_channel_datastore_find(chan, &odbc_info, data);
-       if (!store) /* Already freed; no big deal. */
-               return 0;
-       ast_channel_datastore_remove(chan, store);
-       ast_datastore_free(store);
+       struct ast_datastore *store;
+
+       ast_channel_lock(chan);
+       store = ast_channel_datastore_find(chan, &odbc_info, data);
+       if (store) {
+               ast_channel_datastore_remove(chan, store);
+               ast_datastore_free(store);
+       }
+       ast_channel_unlock(chan);
        return 0;
 }