Skip to content

Commit c927c83

Browse files
committed
PDO MySQL: Fix leak with libmysqlclient and multiple rowsets
stmt->column_count gets reset before the next_rowset handler is invoked, so we need to fetch the value from the result set instead. Arguably PDO should be separating the destruction of the previous result set and the switch to the next result set more cleanly...
1 parent 54a63d9 commit c927c83

File tree

1 file changed

+29
-46
lines changed

1 file changed

+29
-46
lines changed

ext/pdo_mysql/mysql_statement.c

+29-46
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,43 @@
3030

3131
#ifdef PDO_USE_MYSQLND
3232
# define pdo_mysql_stmt_execute_prepared(stmt) pdo_mysql_stmt_execute_prepared_mysqlnd(stmt)
33-
# define pdo_free_bound_result(res) zval_ptr_dtor(res.zv)
3433
#else
3534
# define pdo_mysql_stmt_execute_prepared(stmt) pdo_mysql_stmt_execute_prepared_libmysql(stmt)
36-
# define pdo_free_bound_result(res) efree(res.buffer)
3735
#endif
3836

3937

38+
static void pdo_mysql_free_result(pdo_mysql_stmt *S)
39+
{
40+
if (S->result) {
41+
#ifndef PDO_USE_MYSQLND
42+
if (S->bound_result) {
43+
/* We can't use stmt->column_count here, because it gets reset before the
44+
* next_rowset handler is called. */
45+
unsigned column_count = mysql_num_fields(S->result);
46+
for (unsigned i = 0; i < column_count; i++) {
47+
efree(S->bound_result[i].buffer);
48+
}
49+
50+
efree(S->bound_result);
51+
efree(S->out_null);
52+
efree(S->out_length);
53+
S->bound_result = NULL;
54+
}
55+
#endif
56+
57+
mysql_free_result(S->result);
58+
S->result = NULL;
59+
}
60+
}
4061

4162
static int pdo_mysql_stmt_dtor(pdo_stmt_t *stmt) /* {{{ */
4263
{
4364
pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
4465

4566
PDO_DBG_ENTER("pdo_mysql_stmt_dtor");
4667
PDO_DBG_INF_FMT("stmt=%p", S->stmt);
47-
if (S->result) {
48-
/* free the resource */
49-
mysql_free_result(S->result);
50-
S->result = NULL;
51-
}
68+
69+
pdo_mysql_free_result(S);
5270
if (S->einfo.errmsg) {
5371
pefree(S->einfo.errmsg, stmt->dbh->is_persistent);
5472
S->einfo.errmsg = NULL;
@@ -68,18 +86,6 @@ static int pdo_mysql_stmt_dtor(pdo_stmt_t *stmt) /* {{{ */
6886
if (S->in_length) {
6987
efree(S->in_length);
7088
}
71-
72-
if (S->bound_result)
73-
{
74-
int i;
75-
for (i = 0; i < stmt->column_count; i++) {
76-
pdo_free_bound_result(S->bound_result[i]);
77-
}
78-
79-
efree(S->bound_result);
80-
efree(S->out_null);
81-
efree(S->out_length);
82-
}
8389
#endif
8490

8591
if (!S->done && !Z_ISUNDEF(stmt->database_object_handle)
@@ -209,15 +215,6 @@ static int pdo_mysql_stmt_execute_prepared_libmysql(pdo_stmt_t *stmt) /* {{{ */
209215
if (S->result) {
210216
int calc_max_length = H->buffered && S->max_length == 1;
211217
S->fields = mysql_fetch_fields(S->result);
212-
if (S->bound_result) {
213-
int i;
214-
for (i = 0; i < stmt->column_count; i++) {
215-
efree(S->bound_result[i].buffer);
216-
}
217-
efree(S->bound_result);
218-
efree(S->out_null);
219-
efree(S->out_length);
220-
}
221218

222219
php_pdo_stmt_set_column_count(stmt, (int)mysql_num_fields(S->result));
223220
S->bound_result = ecalloc(stmt->column_count, sizeof(MYSQL_BIND));
@@ -306,12 +303,7 @@ static int pdo_mysql_stmt_execute_prepared_mysqlnd(pdo_stmt_t *stmt) /* {{{ */
306303
PDO_DBG_RETURN(0);
307304
}
308305

309-
if (S->result) {
310-
/* TODO: add a test to check if we really have zvals here... */
311-
mysql_free_result(S->result);
312-
S->result = NULL;
313-
}
314-
306+
pdo_mysql_free_result(S);
315307
PDO_DBG_RETURN(pdo_mysql_stmt_after_execute_prepared(stmt));
316308
}
317309
/* }}} */
@@ -330,10 +322,7 @@ static int pdo_mysql_stmt_execute(pdo_stmt_t *stmt) /* {{{ */
330322
}
331323

332324
/* ensure that we free any previous unfetched results */
333-
if (S->result) {
334-
mysql_free_result(S->result);
335-
S->result = NULL;
336-
}
325+
pdo_mysql_free_result(S);
337326

338327
if (mysql_real_query(H->server, stmt->active_query_string, stmt->active_query_stringlen) != 0) {
339328
pdo_mysql_error_stmt(stmt);
@@ -355,10 +344,7 @@ static int pdo_mysql_stmt_next_rowset(pdo_stmt_t *stmt) /* {{{ */
355344
if (S->stmt) {
356345
mysql_stmt_free_result(S->stmt);
357346
}
358-
if (S->result) {
359-
mysql_free_result(S->result);
360-
S->result = NULL;
361-
}
347+
pdo_mysql_free_result(S);
362348

363349
#ifdef PDO_USE_MYSQLND
364350
if (S->stmt) {
@@ -845,10 +831,7 @@ static int pdo_mysql_stmt_cursor_closer(pdo_stmt_t *stmt) /* {{{ */
845831
PDO_DBG_INF_FMT("stmt=%p", S->stmt);
846832

847833
S->done = 1;
848-
if (S->result) {
849-
mysql_free_result(S->result);
850-
S->result = NULL;
851-
}
834+
pdo_mysql_free_result(S);
852835
if (S->stmt) {
853836
mysql_stmt_free_result(S->stmt);
854837
}

0 commit comments

Comments
 (0)