summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-10-29 16:42:00 +0100
committerNikita Popov <nikita.ppv@gmail.com>2020-10-29 16:42:00 +0100
commitdd008fd1249dc63b2b98f695f154ba32f0134fff (patch)
treeac7fb38c4ddee8c5634ec9d5575a48a480445f92
parent39532f9c52ef39c629deab3a30c1e56612387396 (diff)
parent8957260094f13e7ae71bba134388d9b24f0171c0 (diff)
downloadphp-git-dd008fd1249dc63b2b98f695f154ba32f0134fff.tar.gz
Merge branch 'PHP-8.0'
* PHP-8.0: Fix bug #72413: Segfault with get_result and PS cursors
-rw-r--r--ext/mysqli/tests/mysqli_stmt_get_result.phpt69
-rw-r--r--ext/mysqlnd/mysqlnd_ps.c12
2 files changed, 60 insertions, 21 deletions
diff --git a/ext/mysqli/tests/mysqli_stmt_get_result.phpt b/ext/mysqli/tests/mysqli_stmt_get_result.phpt
index 2dee92d9ae..74b15dfae3 100644
--- a/ext/mysqli/tests/mysqli_stmt_get_result.phpt
+++ b/ext/mysqli/tests/mysqli_stmt_get_result.phpt
@@ -109,53 +109,84 @@ if (!function_exists('mysqli_stmt_get_result'))
mysqli_stmt_close($stmt);
+ // get_result cannot be used in PS cursor mode
if (!$stmt = mysqli_stmt_init($link))
- printf("[032] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+ printf("[030] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
if (!mysqli_stmt_prepare($stmt, "SELECT id, label FROM test ORDER BY id LIMIT 2"))
+ printf("[031] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+
+ if (!mysqli_stmt_attr_set($stmt, MYSQLI_STMT_ATTR_CURSOR_TYPE, MYSQLI_CURSOR_TYPE_READ_ONLY))
+ printf("[032] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+
+ if (!mysqli_stmt_execute($stmt))
printf("[033] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+ mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
+ try {
+ $res = mysqli_stmt_get_result($stmt);
+ // we expect no segfault if we try to fetch a row because get_result should throw an error or return false
+ mysqli_fetch_assoc($res);
+ } catch (\mysqli_sql_exception $e) {
+ echo $e->getMessage() . "\n";
+ }
+
+ try {
+ $res = $stmt->get_result();
+ // we expect no segfault if we try to fetch a row because get_result should throw an error or return false
+ $res->fetch_assoc();
+ } catch (\mysqli_sql_exception $e) {
+ echo $e->getMessage() . "\n";
+ }
+ mysqli_report(MYSQLI_REPORT_OFF);
+
+ if (!$stmt = mysqli_stmt_init($link))
+ printf("[034] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+ if (!mysqli_stmt_prepare($stmt, "SELECT id, label FROM test ORDER BY id LIMIT 2"))
+ printf("[035] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+
if (!mysqli_stmt_execute($stmt))
- printf("[034] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+ printf("[036] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
$id = NULL;
$label = NULL;
if (true !== ($tmp = mysqli_stmt_bind_result($stmt, $id, $label)))
- printf("[035] Expecting boolean/true, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
+ printf("[037] Expecting boolean/true, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
if (!is_object($tmp = $result = mysqli_stmt_get_result($stmt)))
- printf("[036] Expecting array, got %s/%s, [%d] %s\n",
+ printf("[038] Expecting array, got %s/%s, [%d] %s\n",
gettype($tmp), var_export($tmp, 1),
mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
if (false !== ($tmp = mysqli_stmt_fetch($stmt)))
- printf("[037] Expecting boolean/false, got %s/%s, [%d] %s\n",
+ printf("[039] Expecting boolean/false, got %s/%s, [%d] %s\n",
gettype($tmp), $tmp, mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
- printf("[038] [%d] [%s]\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
- printf("[039] [%d] [%s]\n", mysqli_errno($link), mysqli_error($link));
+ printf("[040] [%d] [%s]\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+ printf("[041] [%d] [%s]\n", mysqli_errno($link), mysqli_error($link));
while ($row = mysqli_fetch_assoc($result)) {
var_dump($row);
}
mysqli_free_result($result);
- if (!mysqli_kill($link, mysqli_thread_id($link)))
- printf("[040] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+ if (!mysqli_kill($link, mysqli_thread_id($link)))
+ printf("[042] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
- if (false !== ($tmp = mysqli_stmt_get_result($stmt)))
- printf("[041] Expecting false, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
+ if (false !== ($tmp = mysqli_stmt_get_result($stmt)))
+ printf("[043] Expecting false, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
- mysqli_stmt_close($stmt);
+ mysqli_stmt_close($stmt);
- try {
+ try {
mysqli_stmt_fetch($stmt);
} catch (Error $exception) {
- echo $exception->getMessage() . "\n";
+ echo $exception->getMessage(), "\n";
}
- mysqli_close($link);
+ mysqli_close($link);
- print "done!";
+ print "done!";
?>
--CLEAN--
<?php
@@ -165,8 +196,10 @@ if (!function_exists('mysqli_stmt_get_result'))
mysqli_stmt object is not fully initialized
mysqli_stmt object is not fully initialized
mysqli_stmt object is not fully initialized
-[038] [2014] [Commands out of sync; you can't run this command now]
-[039] [0] []
+mysqli_stmt_get_result() cannot be used with cursors
+get_result() cannot be used with cursors
+[040] [2014] [Commands out of sync; you can't run this command now]
+[041] [0] []
array(2) {
["id"]=>
int(1)
diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c
index 226a2d6e9b..55da87fdf0 100644
--- a/ext/mysqlnd/mysqlnd_ps.c
+++ b/ext/mysqlnd/mysqlnd_ps.c
@@ -151,13 +151,19 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s)
}
if (stmt->cursor_exists) {
- /* Silently convert buffered to unbuffered, for now */
- DBG_RETURN(s->m->use_result(s));
+ /* Prepared statement cursors are not supported as of yet */
+ char * msg;
+ mnd_sprintf(&msg, 0, "%s() cannot be used with cursors", get_active_function_name());
+ SET_CLIENT_ERROR(stmt->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, msg);
+ if (msg) {
+ mnd_sprintf_free(msg);
+ }
+ DBG_RETURN(NULL);
}
/* Nothing to store for UPSERT/LOAD DATA*/
if (GET_CONNECTION_STATE(&conn->state) != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) {
- SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
+ SET_CLIENT_ERROR(stmt->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
DBG_RETURN(NULL);
}