mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
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.
This commit is contained in:
parent
ac0bbea3a8
commit
b27ff62ee0
4 changed files with 53 additions and 3 deletions
4
NEWS
4
NEWS
|
@ -14,6 +14,10 @@ PHP NEWS
|
|||
. Fixed bug #72658 (Locale::lookup() / locale_lookup() hangs if no match
|
||||
found). (Anatol)
|
||||
|
||||
- Mysqlnd:
|
||||
. Fixed bug #71863 (Segfault when EXPLAIN with "Unknown column" error when
|
||||
using MariaDB). (Andrey)
|
||||
|
||||
- Reflection:
|
||||
. Fixed bug #72661 (ReflectionType::__toString crashes with iterable).
|
||||
(Laruence)
|
||||
|
|
37
ext/mysqli/tests/bug71863.phpt
Normal file
37
ext/mysqli/tests/bug71863.phpt
Normal file
|
@ -0,0 +1,37 @@
|
|||
--TEST--
|
||||
Bug #71863 Segfault when EXPLAIN with "Unknown Column" Error
|
||||
--SKIPIF--
|
||||
<?php
|
||||
require_once('skipif.inc');
|
||||
require_once('skipifconnectfailure.inc');
|
||||
require_once("connect.inc");
|
||||
if (!$IS_MYSQLND) {
|
||||
die("skip mysqlnd only test");
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("connect.inc");
|
||||
|
||||
$req = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
|
||||
|
||||
// create db and table for test
|
||||
mysqli_query($req, "DROP TABLE IF EXISTS test_bug_71863") or die(mysqli_error($req));
|
||||
mysqli_query($req, "CREATE TABLE test_bug_71863 (id INT UNSIGNED NOT NULL DEFAULT 0)") or die(mysqli_error($req));
|
||||
|
||||
// segfault if EXPLAIN + "Unknown column" error
|
||||
mysqli_query($req, "EXPLAIN SELECT `id` FROM `test_bug_71863` WHERE `owner_id` = '2' AND `object_id` = '1' AND type = '0'") or die(mysqli_error($req)."\n");
|
||||
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
require_once("connect.inc");
|
||||
if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
|
||||
printf("[c001] [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error());
|
||||
if (!mysqli_query($link, "DROP TABLE IF EXISTS test_bug_71863"))
|
||||
printf("[c002] Cannot drop table, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
|
||||
mysqli_close($link);
|
||||
?>
|
||||
--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'
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue