summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorrfussenegger <richard.fussenegger@trivago.com>2016-09-30 10:49:08 +0200
committerNikita Popov <nikita.ppv@gmail.com>2017-01-12 21:13:39 +0100
commitbd75f9e61375c7632bb55b0d49b470ecd94e8ec7 (patch)
treeba34d0b788bc365aa0ac65b61d9a2e1fe0a6ce18 /ext
parent1ee1f79e27fb4006d0400b38163b2ec0786fd130 (diff)
downloadphp-git-bd75f9e61375c7632bb55b0d49b470ecd94e8ec7.tar.gz
Fix bug #69899
Diffstat (limited to 'ext')
-rw-r--r--ext/mysqli/tests/bug69899.phpt38
-rw-r--r--ext/mysqlnd/mysqlnd_ps.c5
2 files changed, 41 insertions, 2 deletions
diff --git a/ext/mysqli/tests/bug69899.phpt b/ext/mysqli/tests/bug69899.phpt
new file mode 100644
index 0000000000..177b5e3dce
--- /dev/null
+++ b/ext/mysqli/tests/bug69899.phpt
@@ -0,0 +1,38 @@
+--TEST--
+Bug #69899: Segfault on stmt close after free_result with mysqlnd.
+--DESCRIPTION--
+The segfault happens only if the database connection was already closed and
+free_result is called on a prepared statement followed by closing that
+statement. This is due to mysqlnd_stmt::free_result (mysqlnd_ps.c) which
+unconditionally sets the connection of the statement to ready, despite the fact
+that it might already be closed.
+--SKIPIF--
+<?php
+require_once __DIR__ . '/skipif.inc';
+require_once __DIR__ . '/skipifconnectfailure.inc';
+require_once __DIR__ . '/connect.inc';
+if (!$IS_MYSQLND) {
+ die('mysqlnd only');
+}
+?>
+--FILE--
+<?php
+
+require_once __DIR__ . '/connect.inc';
+
+mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
+
+$mysqli = new mysqli($host, $user, $passwd, $db, $port, $socket);
+$stmt = $mysqli->prepare('SELECT 1');
+
+var_dump(
+ $mysqli->close(),
+ $stmt->free_result(),
+ $stmt->close()
+);
+
+?>
+--EXPECT--
+bool(true)
+NULL
+bool(true)
diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c
index 670ea99038..2631e4a797 100644
--- a/ext/mysqlnd/mysqlnd_ps.c
+++ b/ext/mysqlnd/mysqlnd_ps.c
@@ -2005,8 +2005,9 @@ MYSQLND_METHOD(mysqlnd_stmt, free_result)(MYSQLND_STMT * const s)
stmt->state = MYSQLND_STMT_PREPARED;
}
- /* Line is free! */
- CONN_SET_STATE(stmt->conn, CONN_READY);
+ if (CONN_GET_STATE(stmt->conn) != CONN_QUIT_SENT) {
+ CONN_SET_STATE(stmt->conn, CONN_READY);
+ }
DBG_RETURN(PASS);
}