[php-src] Issue #12107: When running a stored procedure (that returns a result set) twice, PHP crashes
| From: | DeveloperRob | Date: | Sat, 02 Sep 2023 17:30:05 +0000 |
| Subject: | [php-src] Issue #12107: When running a stored procedure (that returns a result set) twice, PHP crashes | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-245317@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/12107
Author: DeveloperRob
### Description
The following code:
```php
<?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";
```
```sql
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 is then no longer truthy)
```php
// ...
$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)