Skip to content

Commit 1752393

Browse files
committed
Fix #79084: mysqlnd may fetch wrong column indexes with MYSQLI_BOTH
Column names can be numeric strings, so we have to make sure to insert the column values with the appropriate numeric keys, instead of adding them.
1 parent f6dea34 commit 1752393

File tree

4 files changed

+153
-6
lines changed

4 files changed

+153
-6
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ PHP NEWS
66
. Fixed bug #79078 (Hypothetical use-after-free in curl_multi_add_handle()).
77
(cmb)
88

9+
- MySQLnd:
10+
. Fixed bug #79084 (mysqlnd may fetch wrong column indexes with MYSQLI_BOTH).
11+
(cmb)
12+
913
23 Jan 2020, PHP 7.3.14
1014

1115
- Core

ext/mysqli/tests/bug79084.phpt

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
--TEST--
2+
Bug #79084 (mysqlnd may fetch wrong column indexes with MYSQLI_BOTH)
3+
--SKIPIF--
4+
<?php
5+
require_once('skipif.inc');
6+
require_once('skipifconnectfailure.inc');
7+
?>
8+
--FILE--
9+
<?php
10+
require_once('connect.inc');
11+
$sql = "SELECT 0 as `2007`, 0 as `2008`, 0 as `2020`";
12+
13+
// unbuffered
14+
$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
15+
$link->real_query($sql);
16+
$res = $link->use_result();
17+
$row = $res->fetch_array();
18+
var_dump($row);
19+
$link->close();
20+
21+
// buffered
22+
ini_set('mysqlnd.fetch_data_copy', false);
23+
$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
24+
$res = $link->query($sql);
25+
$row = $res->fetch_array();
26+
var_dump($row);
27+
$link->close();
28+
29+
// buffered copies
30+
ini_set('mysqlnd.fetch_data_copy', true);
31+
$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
32+
$res = $link->query($sql);
33+
$row = $res->fetch_array();
34+
var_dump($row);
35+
$link->close();
36+
?>
37+
--EXPECT--
38+
array(6) {
39+
[0]=>
40+
string(1) "0"
41+
[2007]=>
42+
string(1) "0"
43+
[1]=>
44+
string(1) "0"
45+
[2008]=>
46+
string(1) "0"
47+
[2]=>
48+
string(1) "0"
49+
[2020]=>
50+
string(1) "0"
51+
}
52+
array(6) {
53+
[0]=>
54+
string(1) "0"
55+
[2007]=>
56+
string(1) "0"
57+
[1]=>
58+
string(1) "0"
59+
[2008]=>
60+
string(1) "0"
61+
[2]=>
62+
string(1) "0"
63+
[2020]=>
64+
string(1) "0"
65+
}
66+
array(6) {
67+
[0]=>
68+
string(1) "0"
69+
[2007]=>
70+
string(1) "0"
71+
[1]=>
72+
string(1) "0"
73+
[2008]=>
74+
string(1) "0"
75+
[2]=>
76+
string(1) "0"
77+
[2020]=>
78+
string(1) "0"
79+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
--TEST--
2+
Bug #79084 (mysqlnd may fetch wrong column indexes with MYSQLI_BOTH) - collision
3+
--SKIPIF--
4+
<?php
5+
require_once('skipif.inc');
6+
require_once('skipifconnectfailure.inc');
7+
?>
8+
--FILE--
9+
<?php
10+
require_once('connect.inc');
11+
$sql = "SELECT 11111 as `1`, 22222 as `2`";
12+
13+
// unbuffered
14+
$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
15+
$link->real_query($sql);
16+
$res = $link->use_result();
17+
$row = $res->fetch_array();
18+
var_dump($row);
19+
$link->close();
20+
21+
// buffered
22+
ini_set('mysqlnd.fetch_data_copy', false);
23+
$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
24+
$res = $link->query($sql);
25+
$row = $res->fetch_array();
26+
var_dump($row);
27+
$link->close();
28+
29+
// buffered copies
30+
ini_set('mysqlnd.fetch_data_copy', true);
31+
$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
32+
$res = $link->query($sql);
33+
$row = $res->fetch_array();
34+
var_dump($row);
35+
$link->close();
36+
?>
37+
--EXPECT--
38+
array(3) {
39+
[0]=>
40+
string(5) "11111"
41+
[1]=>
42+
string(5) "11111"
43+
[2]=>
44+
string(5) "22222"
45+
}
46+
array(3) {
47+
[0]=>
48+
string(5) "11111"
49+
[1]=>
50+
string(5) "11111"
51+
[2]=>
52+
string(5) "22222"
53+
}
54+
array(3) {
55+
[0]=>
56+
string(5) "11111"
57+
[1]=>
58+
string(5) "11111"
59+
[2]=>
60+
string(5) "22222"
61+
}

ext/mysqlnd/mysqlnd_result.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -842,8 +842,9 @@ MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row)(MYSQLND_RES * result, void
842842
const size_t len = (Z_TYPE_P(data) == IS_STRING)? Z_STRLEN_P(data) : 0;
843843

844844
if (flags & MYSQLND_FETCH_NUM) {
845-
Z_TRY_ADDREF_P(data);
846-
zend_hash_next_index_insert(row_ht, data);
845+
if (zend_hash_index_add(row_ht, i, data) != NULL) {
846+
Z_TRY_ADDREF_P(data);
847+
}
847848
}
848849
if (flags & MYSQLND_FETCH_ASSOC) {
849850
/* zend_hash_quick_update needs length + trailing zero */
@@ -1099,8 +1100,9 @@ MYSQLND_METHOD(mysqlnd_result_buffered_zval, fetch_row)(MYSQLND_RES * result, vo
10991100
set->lengths[i] = (Z_TYPE_P(data) == IS_STRING)? Z_STRLEN_P(data) : 0;
11001101

11011102
if (flags & MYSQLND_FETCH_NUM) {
1102-
Z_TRY_ADDREF_P(data);
1103-
zend_hash_next_index_insert(Z_ARRVAL_P(row), data);
1103+
if (zend_hash_index_add(Z_ARRVAL_P(row), i, data) != NULL) {
1104+
Z_TRY_ADDREF_P(data);
1105+
}
11041106
}
11051107
if (flags & MYSQLND_FETCH_ASSOC) {
11061108
/* zend_hash_quick_update needs length + trailing zero */
@@ -1195,8 +1197,9 @@ MYSQLND_METHOD(mysqlnd_result_buffered_c, fetch_row)(MYSQLND_RES * result, void
11951197
set->lengths[i] = (Z_TYPE_P(data) == IS_STRING)? Z_STRLEN_P(data) : 0;
11961198

11971199
if (flags & MYSQLND_FETCH_NUM) {
1198-
Z_TRY_ADDREF_P(data);
1199-
zend_hash_next_index_insert(Z_ARRVAL_P(row), data);
1200+
if (zend_hash_index_add(Z_ARRVAL_P(row), i, data)) {
1201+
Z_TRY_ADDREF_P(data);
1202+
}
12001203
}
12011204
if (flags & MYSQLND_FETCH_ASSOC) {
12021205
/* zend_hash_quick_update needs length + trailing zero */

0 commit comments

Comments
 (0)