[asterisk-commits] addons/res config mysql: Don't mutate va list parameters (asterisk[11])

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Apr 29 12:25:28 CDT 2015


Mark Michelson has submitted this change and it was merged.

Change subject: addons/res_config_mysql: Don't mutate va_list parameters
......................................................................


addons/res_config_mysql: Don't mutate va_list parameters

The realtime API passes down the va_list argument to each RT engine in
failover chain until one succeeds. MySQL engine used to access the
variable argument list with va_arg, which mutates the va_list, so the
next engine in failover chain gets invalid agrument list.
This patch uses va_copy to preserve the original va_list argument intact.

ASTERISK-19538 #close
Reported by: alexat
Tested by: Ivan Poddubny

Change-Id: I7738b9f98bde81ddfbc2c0fa579d85a0c3e580ae
---
M addons/res_config_mysql.c
1 file changed, 60 insertions(+), 23 deletions(-)

Approvals:
  Mark Michelson: Looks good to me, approved; Verified
  Joshua Colp: Looks good to me, but someone else must approve



diff --git a/addons/res_config_mysql.c b/addons/res_config_mysql.c
index 71f21db..5ca9b4a 100644
--- a/addons/res_config_mysql.c
+++ b/addons/res_config_mysql.c
@@ -330,6 +330,7 @@
 	char *op;
 	const char *newparam, *newval;
 	struct ast_variable *var=NULL, *prev=NULL;
+	va_list aq;
 
 	if (!(dbh = find_database(database, 0))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Invalid database specified: %s (check res_mysql.conf)\n", database);
@@ -343,14 +344,17 @@
 	}
 
 	/* Get the first parameter and first value in our list of passed paramater/value pairs */
-	if (!(newparam = va_arg(ap, const char *)) || !(newval = va_arg(ap, const char *)))  {
+	va_copy(aq, ap);
+	if (!(newparam = va_arg(aq, const char *)) || !(newval = va_arg(aq, const char *)))  {
 		ast_log(LOG_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
+		va_end(aq);
 		release_database(dbh);
 		return NULL;
 	}
 
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
 	if (!mysql_reconnect(dbh)) {
+		va_end(aq);
 		release_database(dbh);
 		return NULL;
 	}
@@ -365,8 +369,8 @@
 
 	ESCAPE_STRING(buf, newval);
 	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, ast_str_buffer(buf));
-	while ((newparam = va_arg(ap, const char *))) {
-		newval = va_arg(ap, const char *);
+	while ((newparam = va_arg(aq, const char *))) {
+		newval = va_arg(aq, const char *);
 		if (!strchr(newparam, ' ')) 
 			op = " ="; 
 		else
@@ -380,6 +384,7 @@
 	/* Execution. */
 	if (mysql_real_query(&dbh->handle, ast_str_buffer(sql), ast_str_strlen(sql))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database: %s\n", mysql_error(&dbh->handle));
+		va_end(aq);
 		release_database(dbh);
 		return NULL;
 	}
@@ -411,6 +416,7 @@
 		ast_debug(1, "MySQL RealTime: Could not find any rows in table %s.\n", table);
 	}
 
+	va_end(aq);
 	release_database(dbh);
 	mysql_free_result(result);
 
@@ -434,6 +440,7 @@
 	struct ast_variable *var = NULL;
 	struct ast_config *cfg = NULL;
 	struct ast_category *cat = NULL;
+	va_list aq;
 
 	if (!(dbh = find_database(database, 0))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Invalid database specified: '%s' (check res_mysql.conf)\n", database);
@@ -454,8 +461,10 @@
 	}
 
 	/* Get the first parameter and first value in our list of passed paramater/value pairs */
-	if (!(newparam = va_arg(ap, const char *)) || !(newval = va_arg(ap, const char *)))  {
+	va_copy(aq, ap);
+	if (!(newparam = va_arg(aq, const char *)) || !(newval = va_arg(aq, const char *)))  {
 		ast_log(LOG_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
+		va_end(aq);
 		ast_config_destroy(cfg);
 		release_database(dbh);
 		return NULL;
@@ -468,6 +477,7 @@
 
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
 	if (!mysql_reconnect(dbh)) {
+		va_end(aq);
 		release_database(dbh);
 		ast_config_destroy(cfg);
 		return NULL;
@@ -483,8 +493,8 @@
 
 	ESCAPE_STRING(buf, newval);
 	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, ast_str_buffer(buf));
-	while ((newparam = va_arg(ap, const char *))) {
-		newval = va_arg(ap, const char *);
+	while ((newparam = va_arg(aq, const char *))) {
+		newval = va_arg(aq, const char *);
 		if (!strchr(newparam, ' ')) op = " ="; else op = "";
 		ESCAPE_STRING(buf, newval);
 		ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(buf));
@@ -499,6 +509,7 @@
 	/* Execution. */
 	if (mysql_real_query(&dbh->handle, ast_str_buffer(sql), ast_str_strlen(sql))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database: %s\n", mysql_error(&dbh->handle));
+		va_end(aq);
 		release_database(dbh);
 		ast_config_destroy(cfg);
 		return NULL;
@@ -534,6 +545,7 @@
 		ast_debug(1, "MySQL RealTime: Could not find any rows in table %s.\n", table);
 	}
 
+	va_end(aq);
 	release_database(dbh);
 	mysql_free_result(result);
 
@@ -548,6 +560,7 @@
 	struct ast_str *sql = ast_str_thread_get(&sql_buf, 100), *buf = ast_str_thread_get(&scratch_buf, 100);
 	struct tables *table;
 	struct columns *column = NULL;
+	va_list aq;
 
 	if (!(dbh = find_database(database, 1))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Invalid database specified: '%s' (check res_mysql.conf)\n", database);
@@ -574,8 +587,10 @@
 	}
 
 	/* Get the first parameter and first value in our list of passed paramater/value pairs */
-	if (!(newparam = va_arg(ap, const char *)) || !(newval = va_arg(ap, const char *)))  {
+	va_copy(aq, ap);
+	if (!(newparam = va_arg(aq, const char *)) || !(newval = va_arg(aq, const char *)))  {
 		ast_log(LOG_WARNING, "MySQL RealTime: Realtime update requires at least 1 parameter and 1 value to update.\n");
+		va_end(aq);
 		release_table(table);
 		release_database(dbh);
 		return -1;
@@ -584,6 +599,7 @@
 	/* Check that the column exists in the table */
 	if (!(column = find_column(table, newparam))) {
 		ast_log(LOG_ERROR, "MySQL RealTime: Updating column '%s', but that column does not exist within the table '%s' (first pair MUST exist)!\n", newparam, tablename);
+		va_end(aq);
 		release_table(table);
 		release_database(dbh);
 		return -1;
@@ -591,6 +607,7 @@
 
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
 	if (!mysql_reconnect(dbh)) {
+		va_end(aq);
 		release_table(table);
 		release_database(dbh);
 		return -1;
@@ -607,8 +624,8 @@
 		internal_require(database, tablename, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
 	}
 
-	while ((newparam = va_arg(ap, const char *))) {
-		newval = va_arg(ap, const char *);
+	while ((newparam = va_arg(aq, const char *))) {
+		newval = va_arg(aq, const char *);
 
 		/* If the column is not within the table, then skip it */
 		if (!(column = find_column(table, newparam))) {
@@ -624,6 +641,8 @@
 			internal_require(database, tablename, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
 		}
 	}
+
+	va_end(aq);
 
 	ESCAPE_STRING(buf, lookup);
 	ast_str_append(&sql, 0, " WHERE `%s` = '%s'", keyfield, ast_str_buffer(buf));
@@ -663,6 +682,7 @@
 	struct ast_str *where = ast_str_thread_get(&sql2_buf, 100);
 	struct tables *table;
 	struct columns *column = NULL;
+	va_list aq;
 
 	if (!tablename) {
 		ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
@@ -697,15 +717,18 @@
 	}
 
 	first = 1;
-	while ((newparam = va_arg(ap, const char *))) {
+	va_copy(aq, ap);
+	while ((newparam = va_arg(aq, const char *))) {
 		if (!(column = find_column(table, newparam))) {
 			ast_log(LOG_ERROR, "Updating on column '%s', but that column does not exist within the table '%s'!\n", newparam, tablename);
+			va_end(aq);
 			release_table(table);
 			release_database(dbh);
 			return -1;
 		}
-		if (!(newval = va_arg(ap, const char *))) {
+		if (!(newval = va_arg(aq, const char *))) {
 			ast_log(LOG_ERROR, "Invalid arguments: no value specified for column '%s' on '%s@%s'\n", newparam, tablename, database);
+			va_end(aq);
 			release_table(table);
 			release_database(dbh);
 			return -1;
@@ -721,9 +744,10 @@
 	}
 
 	first = 1;
-	while ((newparam = va_arg(ap, const char *))) {
-		if (!(newval = va_arg(ap, const char *))) {
+	while ((newparam = va_arg(aq, const char *))) {
+		if (!(newval = va_arg(aq, const char *))) {
 			ast_log(LOG_ERROR, "Invalid arguments: no value specified for column '%s' on '%s@%s'\n", newparam, tablename, database);
+			va_end(aq);
 			release_table(table);
 			release_database(dbh);
 			return -1;
@@ -744,6 +768,8 @@
 			internal_require(database, tablename, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
 		}
 	}
+
+	va_end(aq);
 
 	release_table(table);
 
@@ -781,6 +807,7 @@
 	struct ast_str *sql2 = ast_str_thread_get(&sql2_buf, 16);
 	struct ast_str *buf = ast_str_thread_get(&scratch_buf, 16);
 	const char *newparam, *newval;
+	va_list aq;
 
 	if (!(dbh = find_database(database, 1))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Invalid database specified: '%s' (check res_mysql.conf)\n", database);
@@ -793,13 +820,16 @@
 		return -1;
 	}
 	/* Get the first parameter and first value in our list of passed paramater/value pairs */
-	if (!(newparam = va_arg(ap, const char *)) || !(newval = va_arg(ap, const char *))) {
+	va_copy(aq, ap);
+	if (!(newparam = va_arg(aq, const char *)) || !(newval = va_arg(aq, const char *))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Realtime storage requires at least 1 parameter and 1 value to search on.\n");
+		va_end(aq);
 		release_database(dbh);
 		return -1;
 	}
 	/* Must connect to the server before anything else, as the escape function requires the mysql handle. */
 	if (!mysql_reconnect(dbh)) {
+		va_end(aq);
 		release_database(dbh);
 		return -1;
 	}
@@ -811,8 +841,8 @@
 
 	internal_require(database, table, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
 
-	while ((newparam = va_arg(ap, const char *))) {
-		if ((newval = va_arg(ap, const char *))) {
+	while ((newparam = va_arg(aq, const char *))) {
+		if ((newval = va_arg(aq, const char *))) {
 			ESCAPE_STRING(buf, newval);
 		} else {
 			ast_str_reset(buf);
@@ -822,6 +852,7 @@
 			ast_str_append(&sql2, 0, ", '%s'", ast_str_buffer(buf));
 		}
 	}
+	va_end(aq);
 	ast_str_append(&sql, 0, "%s)", ast_str_buffer(sql2));
 	ast_debug(1,"MySQL RealTime: Insert SQL: %s\n", ast_str_buffer(sql));
 
@@ -853,6 +884,7 @@
 	struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
 	struct ast_str *buf = ast_str_thread_get(&scratch_buf, 16);
 	const char *newparam, *newval;
+	va_list aq;
 
 	if (!(dbh = find_database(database, 1))) {
 		ast_log(LOG_WARNING, "MySQL RealTime: Invalid database specified: '%s' (check res_mysql.conf)\n", database);
@@ -866,8 +898,8 @@
 	}
 
 	/* Get the first parameter and first value in our list of passed paramater/value pairs */
-	/* newparam = va_arg(ap, const char *);
-	newval = va_arg(ap, const char *);*/
+	/* newparam = va_arg(aq, const char *);
+	newval = va_arg(aq, const char *);*/
 	if (ast_strlen_zero(keyfield) || ast_strlen_zero(lookup))  {
 		ast_log(LOG_WARNING, "MySQL RealTime: Realtime destroying requires at least 1 parameter and 1 value to search on.\n");
 		release_database(dbh);
@@ -884,11 +916,13 @@
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
 	ESCAPE_STRING(buf, lookup);
 	ast_str_set(&sql, 0, "DELETE FROM %s WHERE `%s` = '%s'", table, keyfield, ast_str_buffer(buf));
-	while ((newparam = va_arg(ap, const char *))) {
-		newval = va_arg(ap, const char *);
+	va_copy(aq, ap);
+	while ((newparam = va_arg(aq, const char *))) {
+		newval = va_arg(aq, const char *);
 		ESCAPE_STRING(buf, newval);
 		ast_str_append(&sql, 0, " AND `%s` = '%s'", newparam, ast_str_buffer(buf));
 	}
+	va_end(aq);
 
 	ast_debug(1, "MySQL RealTime: Delete SQL: %s\n", ast_str_buffer(sql));
 
@@ -1109,15 +1143,17 @@
 	struct tables *table = find_table(database, tablename);
 	char *elm;
 	int type, size, res = 0, table_altered = 0;
+	va_list aq;
 
 	if (!table) {
 		ast_log(LOG_WARNING, "Table %s not found in database.  This table should exist if you're using realtime.\n", tablename);
 		return -1;
 	}
 
-	while ((elm = va_arg(ap, char *))) {
-		type = va_arg(ap, require_type);
-		size = va_arg(ap, int);
+	va_copy(aq, ap);
+	while ((elm = va_arg(aq, char *))) {
+		type = va_arg(aq, require_type);
+		size = va_arg(aq, int);
 		AST_LIST_TRAVERSE(&table->columns, column, list) {
 			if (strcmp(column->name, elm) == 0) {
 				/* Char can hold anything, as long as it is large enough */
@@ -1338,6 +1374,7 @@
 			}
 		}
 	}
+	va_end(aq);
 	release_table(table);
 
 	/* If we altered the table, we must refresh the cache */

-- 
To view, visit https://gerrit.asterisk.org/277
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I7738b9f98bde81ddfbc2c0fa579d85a0c3e580ae
Gerrit-PatchSet: 1
Gerrit-Project: asterisk
Gerrit-Branch: 11
Gerrit-Owner: Ivan Poddubny <ivan.poddubny at gmail.com>
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Mark Michelson <mmichelson at digium.com>



More information about the asterisk-commits mailing list