Skip to content

Commit ca5d482

Browse files
Yurunsoftkamil-tekiela
authored andcommitted
Fix MySQL Statement has a empty query result when the response field has changed, also Segmentation fault
Closes phpGH-11551.
1 parent dc586b1 commit ca5d482

File tree

4 files changed

+160
-1
lines changed

4 files changed

+160
-1
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ PHP NEWS
2727
. Fixed bug GH-11438 (mysqlnd fails to authenticate with sha256_password
2828
accounts using passwords longer than 19 characters).
2929
(nielsdos, Kamil Tekiela)
30+
. Fixed bug GH-11550 (MySQL Statement has a empty query result when
31+
the response field has changed, also Segmentation fault).
32+
(Yurunsoft)
3033

3134
- Opcache:
3235
. Fixed bug GH-11715 (opcache.interned_strings_buffer either has no effect or

ext/mysqli/tests/gh11550.phpt

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
--TEST--
2+
Bug GH-11550 (MySQL Statement has a empty query result when the response field has changed, also Segmentation fault)
3+
--EXTENSIONS--
4+
mysqli
5+
--SKIPIF--
6+
<?php
7+
require_once 'skipifconnectfailure.inc';
8+
?>
9+
--FILE--
10+
<?php
11+
require_once 'connect.inc';
12+
13+
$link = new \mysqli($host, $user, $passwd, $db, $port, $socket);
14+
15+
$link->query(<<<'SQL'
16+
CREATE TABLE `test_gh11550` (
17+
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
18+
`name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
19+
PRIMARY KEY (`id`) USING BTREE,
20+
INDEX `name`(`name`) USING BTREE
21+
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
22+
SQL);
23+
$link->query(<<<'SQL'
24+
INSERT INTO `test_gh11550` (`name`) VALUES ('test1');
25+
SQL);
26+
27+
$stmt = $link->prepare('select * from test_gh11550');
28+
var_dump('mysqli-1:', $stmt->execute(), $stmt->get_result()->fetch_all());
29+
30+
$link->query(<<<'SQL'
31+
ALTER TABLE `test_gh11550`
32+
ADD COLUMN `a` varchar(255) NOT NULL DEFAULT '';
33+
SQL);
34+
35+
var_dump('mysqli-2:', $stmt->execute(), $stmt->get_result()->fetch_all());
36+
echo 'Done';
37+
?>
38+
--CLEAN--
39+
<?php
40+
require_once 'connect.inc';
41+
42+
$link = new \mysqli($host, $user, $passwd, $db, $port, $socket);
43+
$link->query('DROP TABLE IF EXISTS test_gh11550');
44+
?>
45+
--EXPECT--
46+
string(9) "mysqli-1:"
47+
bool(true)
48+
array(1) {
49+
[0]=>
50+
array(2) {
51+
[0]=>
52+
int(1)
53+
[1]=>
54+
string(5) "test1"
55+
}
56+
}
57+
string(9) "mysqli-2:"
58+
bool(true)
59+
array(1) {
60+
[0]=>
61+
array(3) {
62+
[0]=>
63+
int(1)
64+
[1]=>
65+
string(5) "test1"
66+
[2]=>
67+
string(0) ""
68+
}
69+
}
70+
Done

ext/mysqlnd/mysqlnd_result.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,12 @@ mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * s)
286286
COM_STMT_EXECUTE (even if it is not necessary), so either this or
287287
previous branch always works.
288288
*/
289+
if (rset_header.field_count != stmt->result->field_count) {
290+
stmt->result->m.free_result(stmt->result, TRUE);
291+
stmt->result = conn->m->result_init(rset_header.field_count);
292+
}
293+
result = stmt->result;
289294
}
290-
result = stmt->result;
291295
}
292296
if (!result) {
293297
SET_OOM_ERROR(conn->error_info);

ext/pdo_mysql/tests/gh11550.phpt

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
--TEST--
2+
Bug GH-11550 (MySQL Statement has a empty query result when the response field has changed, also Segmentation fault)
3+
--EXTENSIONS--
4+
pdo
5+
pdo_mysql
6+
--SKIPIF--
7+
<?php
8+
require_once __DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc';
9+
MySQLPDOTest::skip();
10+
?>
11+
--FILE--
12+
<?php
13+
require_once __DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc';
14+
$pdo = MySQLPDOTest::factory();
15+
16+
$pdo->exec(<<<'SQL'
17+
CREATE TABLE `test_gh11550` (
18+
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
19+
`name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
20+
PRIMARY KEY (`id`) USING BTREE,
21+
INDEX `name`(`name`) USING BTREE
22+
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
23+
SQL);
24+
$pdo->exec(<<<'SQL'
25+
INSERT INTO `test_gh11550` (`name`) VALUES ('test1');
26+
SQL);
27+
28+
$stmt = $pdo->prepare('select * from test_gh11550');
29+
var_dump('PDO-1:', $stmt->execute(), $stmt->fetchAll());
30+
31+
$stmt->closeCursor(); // Optional. Segmentation fault (core dumped)
32+
33+
$pdo->exec(<<<'SQL'
34+
ALTER TABLE `test_gh11550`
35+
ADD COLUMN `a` varchar(255) NOT NULL DEFAULT '';
36+
SQL);
37+
38+
var_dump('PDO-2:', $stmt->execute(), $stmt->fetchAll());
39+
echo 'Done';
40+
?>
41+
--CLEAN--
42+
<?php
43+
require_once __DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc';
44+
$pdo = MySQLPDOTest::factory();
45+
$pdo->query('DROP TABLE IF EXISTS test_gh11550');
46+
?>
47+
--EXPECT--
48+
string(6) "PDO-1:"
49+
bool(true)
50+
array(1) {
51+
[0]=>
52+
array(4) {
53+
["id"]=>
54+
int(1)
55+
[0]=>
56+
int(1)
57+
["name"]=>
58+
string(5) "test1"
59+
[1]=>
60+
string(5) "test1"
61+
}
62+
}
63+
string(6) "PDO-2:"
64+
bool(true)
65+
array(1) {
66+
[0]=>
67+
array(6) {
68+
["id"]=>
69+
int(1)
70+
[0]=>
71+
int(1)
72+
["name"]=>
73+
string(5) "test1"
74+
[1]=>
75+
string(5) "test1"
76+
["a"]=>
77+
string(0) ""
78+
[2]=>
79+
string(0) ""
80+
}
81+
}
82+
Done

0 commit comments

Comments
 (0)