|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #73210 Segfault with stmt read only cursor and get_result due to double closing
Submitted: 2016-09-30 11:28 UTC Modified: 2020-12-18 09:33 UTC
Avg. Score:3.7 ± 0.9
Reproduced:3 of 3 (100.0%)
Same Version:2 (66.7%)
Same OS:1 (33.3%)
From: richard dot fussenegger at trivago dot com Assigned: nikic (profile)
Status: Closed Package: MySQLi related
PHP Version: Irrelevant OS: Irrelevant
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
Block user comment
Status: Assign to:
Bug Type:
From: richard dot fussenegger at trivago dot com
New email:
PHP Version: OS:


 [2016-09-30 11:28 UTC] richard dot fussenegger at trivago dot com
Getting the result of an executed prepared statement that uses a read only cursor results in a segfault because the second close call tries to free the internal result on null. It does not matter which is the first or second close call since stmt gives result a pointer to the result, the one that calls it first is the one that frees it and the other one accesses null.

The access happens in mysqlnd_res::free_result_internal after the if (result->conn) condition where result->conn->m is being called. The m might already point to nowhere because the previous close call already freed it.

Patch will be directly provided as GitHub PR.

Test script:

$mysqli = new mysqli('localhost', 'root', 'keines');

$stmt = $mysqli->prepare('SELECT 1 UNION SELECT 2 UNION SELECT 3');
$result = $stmt->get_result();

// call order does not matter {{{
// }}}


Expected result:
Successful and graceful shutdown of PHP.

Actual result:


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2018-05-04 21:26 UTC]
> Patch will be directly provided as GitHub PR.

FTR: <> didn't really
solve the issue.
 [2019-07-31 20:55 UTC] tekiela246 at gmail dot com
I have a similar problem, but I am not sure if it is the same one. I also get a SEGFAULT when I execute this code:

$mysqli = new mysqli($host, $user, $pass, $db);
$stmtQuery = $mysqli->prepare("SELECT ?, 'name'");
$stmtQuery->bind_result($id, $name);
$stmtQuery->bind_param('i', $i);

I could not get the proper backtrace. I only have this if it helps:
 [2019-08-01 09:09 UTC]
-Status: Open +Status: Verified
 [2019-08-01 09:14 UTC]
Confirming original segfault on 7.2 and valgrind errors on newer versions.
 [2019-08-01 09:33 UTC]
We're freeing the result twice, once directly via free_result and again indirectly via stmt_close.

We could store a back-reference to the stmt in the result and NULL it when the result if freed, but that would only solve the problem for the case where free_result is called before stmt_close. For the reverse case we'd need access to the PHP resource storing the result, which we don't have.

Possibly the result needs to be refcounted?
 [2019-08-01 12:43 UTC]
For PHP 7.2, the segfault already happens when the result is

    php7_debug.dll!mysqlnd_mysqlnd_res_free_result_internal_pub(st_mysqlnd_res * result) Line 348 (c:\php-sdk\phpdev\vc15\x64\php-src-7.2\ext\mysqlnd\mysqlnd_result.c:348)
    php7_debug.dll!mysqlnd_mysqlnd_stmt_free_stmt_result_pub(st_mysqlnd_stmt * const s) Line 2131 (c:\php-sdk\phpdev\vc15\x64\php-src-7.2\ext\mysqlnd\mysqlnd_ps.c:2131)
    php7_debug.dll!mysqlnd_mysqlnd_stmt_free_stmt_content_pub(st_mysqlnd_stmt * const s) Line 2175 (c:\php-sdk\phpdev\vc15\x64\php-src-7.2\ext\mysqlnd\mysqlnd_ps.c:2175)
    php7_debug.dll!mysqlnd_mysqlnd_stmt_close_on_server_priv(st_mysqlnd_stmt * const s, unsigned char implicit) Line 2261 (c:\php-sdk\phpdev\vc15\x64\php-src-7.2\ext\mysqlnd\mysqlnd_ps.c:2261)
    php7_debug.dll!mysqlnd_mysqlnd_stmt_dtor_pub(st_mysqlnd_stmt * const s, unsigned char implicit) Line 2285 (c:\php-sdk\phpdev\vc15\x64\php-src-7.2\ext\mysqlnd\mysqlnd_ps.c:2285)
    php7_debug.dll!zif_mysqli_stmt_close(_zend_execute_data * execute_data, _zval_struct * return_value) Line 2064 (c:\php-sdk\phpdev\vc15\x64\php-src-7.2\ext\mysqli\mysqli_api.c:2064)
    php7_debug.dll!ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER(_zend_execute_data * execute_data) Line 908 (c:\php-sdk\phpdev\vc15\x64\php-src-7.2\Zend\zend_vm_execute.h:908)
    php7_debug.dll!execute_ex(_zend_execute_data * ex) Line 59739 (c:\php-sdk\phpdev\vc15\x64\php-src-7.2\Zend\zend_vm_execute.h:59739)
    php7_debug.dll!zend_execute(_zend_op_array * op_array, _zval_struct * return_value) Line 63777 (c:\php-sdk\phpdev\vc15\x64\php-src-7.2\Zend\zend_vm_execute.h:63777)
    php7_debug.dll!zend_execute_scripts(int type, _zval_struct * retval, int file_count, ...) Line 1499 (c:\php-sdk\phpdev\vc15\x64\php-src-7.2\Zend\zend.c:1499)
    php7_debug.dll!php_execute_script(_zend_file_handle * primary_file) Line 2599 (c:\php-sdk\phpdev\vc15\x64\php-src-7.2\main\main.c:2599)
    php.exe!do_cli(int argc, char * * argv) Line 1012 (c:\php-sdk\phpdev\vc15\x64\php-src-7.2\sapi\cli\php_cli.c:1012)
    php.exe!main(int argc, char * * argv) Line 1403 (c:\php-sdk\phpdev\vc15\x64\php-src-7.2\sapi\cli\php_cli.c:1403)
    php.exe!invoke_main() Line 79 (d:\agent\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:79)
    php.exe!__scrt_common_main_seh() Line 288 (d:\agent\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288)
    php.exe!__scrt_common_main() Line 331 (d:\agent\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:331)
    php.exe!mainCRTStartup() Line 17 (d:\agent\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_main.cpp:17)
    kernel32.dll!00007ffeba257bd4() (Unbekannte Quelle:0)
    ntdll.dll!00007ffebadece71() (Unbekannte Quelle:0)

I set a breakpoint on mysqlnd_result.c:1527[1], and did

  p result->conn // 0x0000016afac76500
  p result->conn // 0x0000016afac9c180

@tekiela246, your problem doesn't seem related to this issue,
so please file a new ticket.

[1] <>
 [2019-08-01 12:50 UTC]
> For PHP 7.2, the segfault already happens when the result is
> freed

No, nonsense.  It's the double free described by @nikic.
 [2019-08-08 07:01 UTC]
@tekiela246, your issue is actually a duplicate of bug #72413.
 [2020-12-18 09:33 UTC]
-Status: Verified +Status: Closed -Assigned To: +Assigned To: nikic
 [2020-12-18 09:33 UTC]
No longer crashes on 7.4 HEAD, presumably fixed by or related changes. (Does valgrind on 7.3.)
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Wed Jan 27 08:01:26 2021 UTC