From: Andrey Hristov Date: Fri, 22 Jul 2016 21:26:26 +0000 (+0300) Subject: Fix for bug #71863 Segfault when EXPLAIN with "Unknown column" error X-Git-Tag: php-7.2.0alpha1~1339^2~4^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=671d22f5de1396ee9b7b42467a41ff0a58df9389;p=php Fix for bug #71863 Segfault when EXPLAIN with "Unknown column" error The reason was that after the big refactoring of mysqlnd at the end of last year code that is initializing the error_info structure in the result set was not added. It existed already for connections and PS. The code that segfaults is hit only with MariaDB because MariaDB sends full metadata about the EXPLAIN query + EOF packet and only then it sends an error packet. MySQL doesn't do that but sends directly an error which is caught (by different code path). As errors during execution (which means after sending meta) are pretty rare there was no test case of MySQL to catch it. --- diff --git a/NEWS b/NEWS index 841aade0d7..be6e8ef39a 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,10 @@ PHP NEWS . Fixed bug #72639 (Segfault when instantiating class that extends IntlCalendar and adds a property). (Laruence) +- Mysqlnd: + . Fixed bug #71863 (Segfault when EXPLAIN with "Unknown column" error when + using MariaDB). (Andrey) + - OpenSSL: . Use strict mode when decoding base64 in openssl_decrypt(). (Lauri Kenttä) diff --git a/ext/mysqli/tests/bug71863.phpt b/ext/mysqli/tests/bug71863.phpt new file mode 100644 index 0000000000..889792822f --- /dev/null +++ b/ext/mysqli/tests/bug71863.phpt @@ -0,0 +1,37 @@ +--TEST-- +Bug #71863 Segfault when EXPLAIN with "Unknown Column" Error +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECTF-- +Warning: mysqli_query(): (42S22/1054): Unknown column 'owner_id' in 'where clause' in %sbug71863.php on line %d +Unknown column 'owner_id' in 'where clause' \ No newline at end of file diff --git a/ext/mysqlnd/mysqlnd_connection.c b/ext/mysqlnd/mysqlnd_connection.c index 701bc282e1..a3300dc6d9 100644 --- a/ext/mysqlnd/mysqlnd_connection.c +++ b/ext/mysqlnd/mysqlnd_connection.c @@ -215,11 +215,11 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_connection_state) MYSQLND_CLASS_METHODS_END; -/* {{{ mysqlnd_upsert_status_init */ +/* {{{ mysqlnd_connection_state_init */ PHPAPI void mysqlnd_connection_state_init(struct st_mysqlnd_connection_state * const state) { - DBG_ENTER("mysqlnd_error_info_init"); + DBG_ENTER("mysqlnd_connection_state_init"); state->m = &MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_connection_state); state->state = CONN_ALLOCED; DBG_VOID_RETURN; diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c index c4aa537eb0..513214d3fa 100644 --- a/ext/mysqlnd/mysqlnd_result.c +++ b/ext/mysqlnd/mysqlnd_result.c @@ -259,6 +259,8 @@ MYSQLND_METHOD(mysqlnd_result_buffered, free_result)(MYSQLND_RES_BUFFERED * cons DBG_ENTER("mysqlnd_result_buffered::free_result"); DBG_INF_FMT("Freeing "MYSQLND_LLU_SPEC" row(s)", set->row_count); + mysqlnd_error_info_free_contents(&set->error_info); + if (set->type == MYSQLND_BUFFERED_TYPE_ZVAL) { MYSQLND_METHOD(mysqlnd_result_buffered_zval, free_result)((MYSQLND_RES_BUFFERED_ZVAL *) set); } if (set->type == MYSQLND_BUFFERED_TYPE_C) { @@ -1954,7 +1956,6 @@ mysqlnd_result_unbuffered_init(const unsigned int field_count, const zend_bool p if (!ret) { DBG_RETURN(NULL); } - if (!(ret->lengths = mnd_pecalloc(field_count, sizeof(size_t), persistent))) { mnd_pefree(ret, persistent); DBG_RETURN(NULL); @@ -1995,6 +1996,10 @@ mysqlnd_result_buffered_zval_init(const unsigned int field_count, const zend_boo if (!ret) { DBG_RETURN(NULL); } + if (FAIL == mysqlnd_error_info_init(&ret->error_info, persistent)) { + mnd_pefree(ret, persistent); + DBG_RETURN(NULL); + } if (!(ret->lengths = mnd_pecalloc(field_count, sizeof(size_t), persistent))) { mnd_pefree(ret, persistent); DBG_RETURN(NULL); @@ -2038,6 +2043,10 @@ mysqlnd_result_buffered_c_init(const unsigned int field_count, const zend_bool p if (!ret) { DBG_RETURN(NULL); } + if (FAIL == mysqlnd_error_info_init(&ret->error_info, persistent)) { + mnd_pefree(ret, persistent); + DBG_RETURN(NULL); + } if (!(ret->lengths = mnd_pecalloc(field_count, sizeof(size_t), persistent))) { mnd_pefree(ret, persistent); DBG_RETURN(NULL);