Skip to content

Commit 0d21a8d

Browse files
committed
Fix GH-12107: When running a stored procedure (that returns a result set) twice, PHP crashes
Closes GH-12771.
1 parent 5e9e9c9 commit 0d21a8d

File tree

3 files changed

+67
-1
lines changed

3 files changed

+67
-1
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ PHP NEWS
1515
. Fixed bug GH-12996 (Incorrect SCRIPT_NAME with Apache ProxyPassMatch when
1616
plus in path). (Jakub Zelenka)
1717

18+
- MySQLnd:
19+
. Fixed bug GH-12107 (When running a stored procedure (that returns a result
20+
set) twice, PHP crashes). (nielsdos)
21+
1822
- OpenSSL:
1923
. Fixed LibreSSL undefined reference when OPENSSL_NO_ENGINE not set.
2024
(David Carlier).

ext/mysqli/tests/gh12107.phpt

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
--TEST--
2+
GH-12107 (When running a stored procedure (that returns a result set) twice, PHP crashes)
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+
$mysqli = new mysqli("$host:$port", $user, $passwd, $db);
14+
15+
$sql = <<<SQL
16+
CREATE PROCEDURE `gh12107`()
17+
BEGIN
18+
SELECT "hello world";
19+
END;
20+
SQL;
21+
$mysqli->query($sql);
22+
23+
echo "Start or run 1\n";
24+
$stmt = $mysqli->prepare("call `gh12107`()");
25+
$stmt->execute();
26+
$stmt->bind_result($output);
27+
var_dump($stmt->fetch());
28+
var_dump($output);
29+
unset($output);
30+
echo "End of run 1\n";
31+
32+
echo "Start or run 2\n";
33+
$stmt->execute();
34+
$stmt->bind_result($output);
35+
var_dump($stmt->fetch());
36+
var_dump($output);
37+
echo "End of run 2\n";
38+
39+
?>
40+
--CLEAN--
41+
<?php
42+
require_once 'connect.inc';
43+
if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
44+
printf("[c001] [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error());
45+
46+
if (!mysqli_query($link, "DROP PROCEDURE IF EXISTS gh12107"))
47+
printf("[c002] Cannot drop procedure, [%d] %s\n", mysqli_errno($link), mysqli_error($link));
48+
49+
mysqli_close($link);
50+
?>
51+
--EXPECT--
52+
Start or run 1
53+
bool(true)
54+
string(11) "hello world"
55+
End of run 1
56+
Start or run 2
57+
bool(true)
58+
string(11) "hello world"
59+
End of run 2

ext/mysqlnd/mysqlnd_ps.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,8 +652,11 @@ MYSQLND_METHOD(mysqlnd_stmt, send_execute)(MYSQLND_STMT * const s, const enum_my
652652
Executed, but the user hasn't started to fetch
653653
This will clean also the metadata, but after the EXECUTE call we will
654654
have it again.
655+
stmt->result may be freed and nullified by free_stmt_result, transitively called from flush.
655656
*/
656-
stmt->result->m.free_result_buffers(stmt->result);
657+
if (stmt->result) {
658+
stmt->result->m.free_result_buffers(stmt->result);
659+
}
657660

658661
stmt->state = MYSQLND_STMT_PREPARED;
659662
} else if (stmt->state < MYSQLND_STMT_PREPARED) {

0 commit comments

Comments
 (0)