Skip to content

When running a stored procedure (that returns a result set) twice, PHP crashes #12107

Closed
@DeveloperRob

Description

@DeveloperRob

Description

The following code:

<?php
$dbConn = new \mysqli(); // Tests done against a MariaDB 10.6 server
$stmt = $dbConn->prepare("call `rmh_internal`.`testSp`()");
$stmt->execute();
$stmt->bind_result($output);
$stmt->fetch();
echo "Run 1\n";
$stmt->execute();
$stmt->bind_result($output);
$stmt->fetch();
echo "Run 2\n";
DELIMITER $$

CREATE OR REPLACE
    PROCEDURE `rmh_internal`.`testSp`()
	BEGIN
		SELECT "String";
	END$$

DELIMITER ;

Resulted in this output:

Run 1
Segmentation fault (core dumped)

But I expected this output instead:

Run 1
Run 2

GDB Output on core dump:

Reading symbols from /usr/bin/php...
Reading symbols from /usr/lib/debug/.build-id/d4/2eafeb7fbba34ede1ab24b596f81bbfc38201b.debug...
[New LWP 1517127]
[New LWP 1517128]
[New LWP 1517129]
[New LWP 1517130]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/aarch64-linux-gnu/libthread_db.so.1".
Core was generated by `php test2.php'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x0000ffffba3d7494 in mysqlnd_mysqlnd_stmt_send_execute_pub (s=0xffffba472080, type=<optimized out>, read_cb=<optimized out>, err_cb=<optimized out>) at ./ext/mysqlnd/mysqlnd_ps.c:656
656     ./ext/mysqlnd/mysqlnd_ps.c: No such file or directory.
[Current thread is 1 (Thread 0xffffbd0eb020 (LWP 1517127))]
(gdb) bt
#0  0x0000ffffba3d7494 in mysqlnd_mysqlnd_stmt_send_execute_pub (s=0xffffba472080, type=<optimized out>, read_cb=<optimized out>, err_cb=<optimized out>) at ./ext/mysqlnd/mysqlnd_ps.c:656
#1  0x0000ffffba3d4ec8 in mysqlnd_mysqlnd_stmt_execute_pub (s=0xffffba472080) at ./ext/mysqlnd/mysqlnd_ps.c:618
#2  0x0000ffffb7bdf414 in zif_mysqli_stmt_execute (execute_data=<optimized out>, return_value=0xffffef9cf8a8) at ./ext/mysqli/mysqli_api.c:466
#3  0x0000aaaab02a4de8 in ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER () at ./Zend/zend_vm_execute.h:1842
#4  execute_ex (ex=0x0) at ./Zend/zend_vm_execute.h:56076
#5  0x0000aaaab02a7a1c in zend_execute (op_array=0xffffba489000, return_value=<optimized out>) at ./Zend/zend_vm_execute.h:60408
#6  0x0000aaaab0223dd4 in zend_execute_scripts (type=type@entry=8, retval=retval@entry=0x0, file_count=file_count@entry=3) at ./Zend/zend.c:1833
#7  0x0000aaaab01bccb0 in php_execute_script (primary_file=0x0, primary_file@entry=0xffffef9d1f20) at ./main/main.c:2542
#8  0x0000aaaab031cefc in do_cli (argc=2, argv=0xaaaaccc8fa40) at ./sapi/cli/php_cli.c:964
#9  0x0000aaaab004cc7c in main (argc=2, argv=<optimized out>) at ./sapi/cli/php_cli.c:1333
(gdb) print s->data->result
$1 = (MYSQLND_RES *) 0x0

My understanding is that s->m->flush(s); will call mysqlnd_stmt_next_result(s) until there is no more results (and therefore stmt->result->m is empty). However that is the extent of my knowledge, I don't know if stmt->result->m.free_result_buffers(stmt->result); is never needed; or if it should be protected by a if(stmt->result) guard. If someone can provide further guidance, I am happy to open a PR - however I suspect it is either going to be easier for someone to fix themselves OR will be more complicated than I realise here.

As a workaround, manually freeing the results in PHP will also prevent the crash (as stmt->result in mysqlnd_ps.c:648 is then no longer truthy)

// ...
$stmt->free_result();
while($stmt->more_results()){
        $stmt->next_result();
        $stmt->free_result();
}
echo "Run 2\n";
// ...

PHP Version

PHP 8.2.10 / PHP 8.1.23

Operating System

Ubuntu 22.04.3 LTS / Windows 11 (64bit)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions