Skip to content

Commit 9c0439e

Browse files
committed
Fix for Bug #52613 crash in mysqlnd
1 parent 00825de commit 9c0439e

File tree

1 file changed

+25
-13
lines changed

1 file changed

+25
-13
lines changed

ext/mysqlnd/mysqlnd_result.c

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,11 @@ static
9191
void mysqlnd_palloc_zval_ptr_dtor(zval **zv, enum_mysqlnd_res_type type, zend_bool * copy_ctor_called TSRMLS_DC)
9292
{
9393
DBG_ENTER("mysqlnd_palloc_zval_ptr_dtor");
94-
94+
if (!zv || !*zv) {
95+
*copy_ctor_called = FALSE;
96+
DBG_ERR_FMT("zv was NULL");
97+
DBG_VOID_RETURN;
98+
}
9599
/*
96100
This zval is not from the cache block.
97101
Thus the refcount is -1 than of a zval from the cache,
@@ -158,17 +162,16 @@ MYSQLND_METHOD(mysqlnd_res, unbuffered_free_last_data)(MYSQLND_RES * result TSRM
158162
for (i = 0; i < result->field_count; i++) {
159163
mysqlnd_palloc_zval_ptr_dtor(&(unbuf->last_row_data[i]), result->type, &copy_ctor_called TSRMLS_CC);
160164
if (copy_ctor_called) {
161-
ctor_called_count++;
165+
++ctor_called_count;
162166
}
163167
}
164168
DBG_INF_FMT("copy_ctor_called_count=%u", ctor_called_count);
165169
/* By using value3 macros we hold a mutex only once, there is no value2 */
166-
MYSQLND_INC_CONN_STATISTIC_W_VALUE3(global_stats,
170+
MYSQLND_INC_CONN_STATISTIC_W_VALUE2(global_stats,
167171
STAT_COPY_ON_WRITE_PERFORMED,
168172
ctor_called_count,
169173
STAT_COPY_ON_WRITE_SAVED,
170-
result->field_count - ctor_called_count,
171-
STAT_COPY_ON_WRITE_PERFORMED, 0);
174+
result->field_count - ctor_called_count);
172175

173176
/* Free last row's zvals */
174177
mnd_efree(unbuf->last_row_data);
@@ -199,30 +202,39 @@ MYSQLND_METHOD(mysqlnd_res, free_buffered_data)(MYSQLND_RES * result TSRMLS_DC)
199202

200203
DBG_INF("Freeing data & row_buffer");
201204
if (set->data) {
205+
unsigned int copy_on_write_performed = 0;
206+
unsigned int copy_on_write_saved = 0;
202207

203208
DBG_INF_FMT("before: real_usage=%lu usage=%lu", zend_memory_usage(TRUE TSRMLS_CC), zend_memory_usage(FALSE TSRMLS_CC));
204209
for (row = set->row_count - 1; row >= 0; row--) {
205210
zval **current_row = set->data + row * field_count;
206211
MYSQLND_MEMORY_POOL_CHUNK *current_buffer = set->row_buffers[row];
207212
int col;
208213

209-
for (col = field_count - 1; col >= 0; --col) {
210-
zend_bool copy_ctor_called;
211-
if (current_row == NULL || current_row[0] == NULL) {
212-
break;/* row that was never initialized */
213-
}
214-
mysqlnd_palloc_zval_ptr_dtor(&(current_row[col]), result->type, &copy_ctor_called TSRMLS_CC);
214+
if (current_row != NULL) {
215+
for (col = field_count - 1; col >= 0; --col) {
216+
if (current_row[col]) {
217+
zend_bool copy_ctor_called;
218+
mysqlnd_palloc_zval_ptr_dtor(&(current_row[col]), result->type, &copy_ctor_called TSRMLS_CC);
215219
#if MYSQLND_DEBUG_MEMORY
216-
DBG_INF_FMT("Copy_ctor_called=%u", copy_ctor_called);
220+
DBG_INF_FMT("Copy_ctor_called=%u", copy_ctor_called);
217221
#endif
218-
MYSQLND_INC_GLOBAL_STATISTIC(copy_ctor_called? STAT_COPY_ON_WRITE_PERFORMED: STAT_COPY_ON_WRITE_SAVED);
222+
if (copy_ctor_called) {
223+
++copy_on_write_performed;
224+
} else {
225+
++copy_on_write_saved;
226+
}
227+
}
228+
}
219229
}
220230
#if MYSQLND_DEBUG_MEMORY
221231
DBG_INF("Freeing current_row & current_buffer");
222232
#endif
223233
current_buffer->free_chunk(current_buffer TSRMLS_CC);
224234
}
225235

236+
MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_COPY_ON_WRITE_PERFORMED, copy_on_write_performed,
237+
STAT_COPY_ON_WRITE_SAVED, copy_on_write_saved);
226238
mnd_pefree(set->data, set->persistent);
227239
set->data = NULL;
228240
}

0 commit comments

Comments
 (0)