com php-src: Fix for bug #71863 Segfault when EXPLAIN with "Unknown column" error: NEWS ext/mysqli/tests/bug71863.phpt ext/mysqlnd/mysqlnd
_connection.c ext/mysqlnd/mysqlnd_result.c
| From: | Nikita Popov | Date: | Mon, 25 Jul 2016 19:59:27 +0000 |
| Subject: | com php-src: Fix for bug #71863 Segfault when EXPLAIN with "Unknown column" error: NEWS ext/mysqli/tests/bug71863.phpt ext/mysqlnd/mysqlnd _connection.c ext/mysqlnd/mysqlnd_result.c |
||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-93394@lists.php.net to get a copy of this message | ||
Commit: b27ff62ee0a40b3784cc032f2431e974a77b28c2
Author: Andrey Hristov <andrey@php.net> Sat, 23 Jul 2016 00:26:26 +0300
Committer: Nikita Popov <nikic@php.net> Mon, 25 Jul 2016 21:59:27 +0200
Parents: ac0bbea3a89334b47995315cd37ca342e89486f2
Branches: PHP-7.1 master
Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=b27ff62ee0a40b3784cc032f2431e974a77b28c2
Log:
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.
Bugs:
https://bugs.php..net/71863
Changed paths:
M NEWS
A ext/mysqli/tests/bug71863..phpt
M ext/mysqlnd/mysqlnd_connection.c
M ext/mysqlnd/mysqlnd_result.c
Diff:
diff --git a/NEWS b/NEWS
index 69728b4..70d667a 100644
--- a/NEWS
+++ b/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)
diff --git a/ext/mysqli/tests/bug71863.phpt b/ext/mysqli/tests/bug71863.phpt
new file mode 100644
index 0000000..8897928
--- /dev/null
+++ b/ext/mysqli/tests/bug71863.phpt
@@ -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'
\ No newline at end of file
diff --git a/ext/mysqlnd/mysqlnd_connection.c b/ext/mysqlnd/mysqlnd_connection.c
index 701bc28..a3300dc 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 c4aa537..513214d 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);