Skip to content

Commit dd008fd

Browse files
committed
Merge branch 'PHP-8.0'
* PHP-8.0: Fix bug #72413: Segfault with get_result and PS cursors
2 parents 39532f9 + 8957260 commit dd008fd

File tree

2 files changed

+60
-21
lines changed

2 files changed

+60
-21
lines changed

ext/mysqli/tests/mysqli_stmt_get_result.phpt

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -109,53 +109,84 @@ if (!function_exists('mysqli_stmt_get_result'))
109109

110110
mysqli_stmt_close($stmt);
111111

112+
// get_result cannot be used in PS cursor mode
112113
if (!$stmt = mysqli_stmt_init($link))
113-
printf("[032] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
114+
printf("[030] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
114115

115116
if (!mysqli_stmt_prepare($stmt, "SELECT id, label FROM test ORDER BY id LIMIT 2"))
117+
printf("[031] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
118+
119+
if (!mysqli_stmt_attr_set($stmt, MYSQLI_STMT_ATTR_CURSOR_TYPE, MYSQLI_CURSOR_TYPE_READ_ONLY))
120+
printf("[032] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
121+
122+
if (!mysqli_stmt_execute($stmt))
116123
printf("[033] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
117124

125+
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
126+
try {
127+
$res = mysqli_stmt_get_result($stmt);
128+
// we expect no segfault if we try to fetch a row because get_result should throw an error or return false
129+
mysqli_fetch_assoc($res);
130+
} catch (\mysqli_sql_exception $e) {
131+
echo $e->getMessage() . "\n";
132+
}
133+
134+
try {
135+
$res = $stmt->get_result();
136+
// we expect no segfault if we try to fetch a row because get_result should throw an error or return false
137+
$res->fetch_assoc();
138+
} catch (\mysqli_sql_exception $e) {
139+
echo $e->getMessage() . "\n";
140+
}
141+
mysqli_report(MYSQLI_REPORT_OFF);
142+
143+
if (!$stmt = mysqli_stmt_init($link))
144+
printf("[034] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
145+
146+
if (!mysqli_stmt_prepare($stmt, "SELECT id, label FROM test ORDER BY id LIMIT 2"))
147+
printf("[035] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
148+
118149
if (!mysqli_stmt_execute($stmt))
119-
printf("[034] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
150+
printf("[036] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
120151

121152
$id = NULL;
122153
$label = NULL;
123154
if (true !== ($tmp = mysqli_stmt_bind_result($stmt, $id, $label)))
124-
printf("[035] Expecting boolean/true, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
155+
printf("[037] Expecting boolean/true, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
125156

126157
if (!is_object($tmp = $result = mysqli_stmt_get_result($stmt)))
127-
printf("[036] Expecting array, got %s/%s, [%d] %s\n",
158+
printf("[038] Expecting array, got %s/%s, [%d] %s\n",
128159
gettype($tmp), var_export($tmp, 1),
129160
mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
130161

131162
if (false !== ($tmp = mysqli_stmt_fetch($stmt)))
132-
printf("[037] Expecting boolean/false, got %s/%s, [%d] %s\n",
163+
printf("[039] Expecting boolean/false, got %s/%s, [%d] %s\n",
133164
gettype($tmp), $tmp, mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
134165

135-
printf("[038] [%d] [%s]\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
136-
printf("[039] [%d] [%s]\n", mysqli_errno($link), mysqli_error($link));
166+
printf("[040] [%d] [%s]\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
167+
printf("[041] [%d] [%s]\n", mysqli_errno($link), mysqli_error($link));
137168
while ($row = mysqli_fetch_assoc($result)) {
138169
var_dump($row);
139170
}
140171
mysqli_free_result($result);
141172

142-
if (!mysqli_kill($link, mysqli_thread_id($link)))
143-
printf("[040] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
173+
if (!mysqli_kill($link, mysqli_thread_id($link)))
174+
printf("[042] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
144175

145-
if (false !== ($tmp = mysqli_stmt_get_result($stmt)))
146-
printf("[041] Expecting false, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
176+
if (false !== ($tmp = mysqli_stmt_get_result($stmt)))
177+
printf("[043] Expecting false, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
147178

148-
mysqli_stmt_close($stmt);
179+
mysqli_stmt_close($stmt);
149180

150-
try {
181+
try {
151182
mysqli_stmt_fetch($stmt);
152183
} catch (Error $exception) {
153-
echo $exception->getMessage() . "\n";
184+
echo $exception->getMessage(), "\n";
154185
}
155186

156-
mysqli_close($link);
187+
mysqli_close($link);
157188

158-
print "done!";
189+
print "done!";
159190
?>
160191
--CLEAN--
161192
<?php
@@ -165,8 +196,10 @@ if (!function_exists('mysqli_stmt_get_result'))
165196
mysqli_stmt object is not fully initialized
166197
mysqli_stmt object is not fully initialized
167198
mysqli_stmt object is not fully initialized
168-
[038] [2014] [Commands out of sync; you can't run this command now]
169-
[039] [0] []
199+
mysqli_stmt_get_result() cannot be used with cursors
200+
get_result() cannot be used with cursors
201+
[040] [2014] [Commands out of sync; you can't run this command now]
202+
[041] [0] []
170203
array(2) {
171204
["id"]=>
172205
int(1)

ext/mysqlnd/mysqlnd_ps.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,19 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s)
151151
}
152152

153153
if (stmt->cursor_exists) {
154-
/* Silently convert buffered to unbuffered, for now */
155-
DBG_RETURN(s->m->use_result(s));
154+
/* Prepared statement cursors are not supported as of yet */
155+
char * msg;
156+
mnd_sprintf(&msg, 0, "%s() cannot be used with cursors", get_active_function_name());
157+
SET_CLIENT_ERROR(stmt->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, msg);
158+
if (msg) {
159+
mnd_sprintf_free(msg);
160+
}
161+
DBG_RETURN(NULL);
156162
}
157163

158164
/* Nothing to store for UPSERT/LOAD DATA*/
159165
if (GET_CONNECTION_STATE(&conn->state) != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) {
160-
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
166+
SET_CLIENT_ERROR(stmt->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
161167
DBG_RETURN(NULL);
162168
}
163169

0 commit comments

Comments
 (0)