php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #80909 Memory leak and possible double free using PDO_ODBC
Submitted: 2021-03-26 19:38 UTC Modified: 2022-02-21 11:49 UTC
From: calvin at cmpct dot info Assigned: cmb (profile)
Status: Closed Package: PDO ODBC
PHP Version: master-Git-2021-03-26 (Git) OS: Debian 9
Private report: No CVE-ID: None
 [2021-03-26 19:38 UTC] calvin at cmpct dot info
Description:
------------
While initially trying to fix another issue (lack of check_liveness, see GH-6805), running a test script on Linux (Debian 9 and Fedora 33 tested), PHP crashes after freeing memory at the end of the script.

I thought it might have been an ODBC driver issue (specifically, the one for Db2i) or with my patches, but after checking out unpatched master, it appears the free and leak is in PHP, according to --enable-debug.

Test script:
---------------
<?php

echo "Hello\n";
$connection = new PDO('odbc:Driver=IBM i Access ODBC Driver;System=host', 'user', 'password', array(PDO::ATTR_PERSISTENT => true));
echo "connected\n";
$stmt = $connection->query("select job_name from table(QSYS2.ACTIVE_JOB_INFO(JOB_NAME_FILTER => 'QZDASOINIT'))");
if ($stmt) {
        var_dump($stmt->fetchAll());
} else {
        var_dump($connection->errorInfo());
}
echo "waiting 20 seconds and pconnecting again \n";
flush();
ob_flush();
sleep(20);
$connection = new PDO('odbc:Driver=IBM i Access ODBC Driver;System=host', 'user', 'password', array(PDO::ATTR_PERSISTENT => true));
$stmt = $connection->query("select job_name from table(QSYS2.ACTIVE_JOB_INFO(JOB_NAME_FILTER => 'QZDASOINIT'))");
if ($stmt) {
        var_dump($stmt->fetchAll());
} else {
        var_dump($connection->errorInfo());
}

?>

Actual result:
--------------
(On Debian)

[Fri Mar 26 16:21:38 2021]  Script:  '/home/calvin/test-pdo-odbc.php'
/home/calvin/php-src/Zend/zend_smart_str.c(153) :  Freeing 0x00007f67dca79300 (224 bytes), script=/home/calvin/test-pdo-odbc.php
=== Total 1 memory leaks detected ===
*** Error in `/tmp/php/bin/php': free(): invalid size: 0x00007f67dca79300 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x70bfb)[0x7f67dfdc8bfb]
/lib/x86_64-linux-gnu/libc.so.6(+0x76fc6)[0x7f67dfdcefc6]
/lib/x86_64-linux-gnu/libc.so.6(+0x7780e)[0x7f67dfdcf80e]
/tmp/php/bin/php(+0x2b6e35)[0x55fec5183e35]
/tmp/php/bin/php(+0x2b7231)[0x55fec5184231]
/tmp/php/bin/php(+0x534235)[0x55fec5401235]
/tmp/php/bin/php(+0x52f231)[0x55fec53fc231]
/tmp/php/bin/php(+0x52f2fd)[0x55fec53fc2fd]
/tmp/php/bin/php(zend_hash_graceful_reverse_destroy+0xc3)[0x55fec53fdb18]
/tmp/php/bin/php(+0x534347)[0x55fec5401347]
/tmp/php/bin/php(+0x5178d7)[0x55fec53e48d7]
/tmp/php/bin/php(php_module_shutdown+0x3b)[0x55fec5350257]
/tmp/php/bin/php(+0x66cc3b)[0x55fec5539c3b]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7f67dfd782e1]
/tmp/php/bin/php(_start+0x2a)[0x55fec4ff8fba]
======= Memory map: ========
55fec4ecd000-55fec5da7000 r-xp 00000000 08:01 29727                      /tmp/php/bin/php
55fec5fec000-55fec60cd000 r--p 00f1f000 08:01 29727                      /tmp/php/bin/php
55fec60cd000-55fec60d4000 rw-p 01000000 08:01 29727                      /tmp/php/bin/php
55fec60d4000-55fec60f2000 rw-p 00000000 00:00 0 
55fec6470000-55fec6641000 rw-p 00000000 00:00 0                          [heap]
7f67d4000000-7f67d4021000 rw-p 00000000 00:00 0 
7f67d4021000-7f67d8000000 ---p 00000000 00:00 0 
7f67dbfad000-7f67dbfaf000 r-xp 00000000 08:01 133284                     /usr/lib/x86_64-linux-gnu/gconv/ISO8859-1.so
7f67dbfaf000-7f67dc1ae000 ---p 00002000 08:01 133284                     /usr/lib/x86_64-linux-gnu/gconv/ISO8859-1.so
7f67dc1ae000-7f67dc1af000 r--p 00001000 08:01 133284                     /usr/lib/x86_64-linux-gnu/gconv/ISO8859-1.so
7f67dc1af000-7f67dc1b0000 rw-p 00002000 08:01 133284                     /usr/lib/x86_64-linux-gnu/gconv/ISO8859-1.so
7f67dc1b0000-7f67dc303000 r-xp 00000000 08:01 7222                       /opt/ibm/iaccess/lib64/libcwbcore.so
7f67dc303000-7f67dc503000 ---p 00153000 08:01 7222                       /opt/ibm/iaccess/lib64/libcwbcore.so
7f67dc503000-7f67dc50c000 r--p 00153000 08:01 7222                       /opt/ibm/iaccess/lib64/libcwbcore.so
7f67dc50c000-7f67dc510000 rw-p 0015c000 08:01 7222                       /opt/ibm/iaccess/lib64/libcwbcore.so
7f67dc510000-7f67dc512000 rw-p 00000000 00:00 0 
7f67dc512000-7f67dc523000 r-xp 00000000 08:01 173845                     /usr/lib/x86_64-linux-gnu/libodbcinst.so.2.0.0
7f67dc523000-7f67dc722000 ---p 00011000 08:01 173845                     /usr/lib/x86_64-linux-gnu/libodbcinst.so.2.0.0
7f67dc722000-7f67dc723000 r--p 00010000 08:01 173845                     /usr/lib/x86_64-linux-gnu/libodbcinst.so.2.0.0
7f67dc723000-7f67dc724000 rw-p 00011000 08:01 173845                     /usr/lib/x86_64-linux-gnu/libodbcinst.so.2.0.0
7f67dc724000-7f67dc727000 rw-p 00000000 00:00 0 
7f67dc727000-7f67dc7f4000 r-xp 00000000 08:01 7221                       /opt/ibm/iaccess/lib64/libcwbodbc.so
7f67dc7f4000-7f67dc9f3000 ---p 000cd000 08:01 7221                       /opt/ibm/iaccess/lib64/libcwbodbc.so
7f67dc9f3000-7f67dc9fb000 r--p 000cc000 08:01 7221                       /opt/ibm/iaccess/lib64/libcwbodbc.so
7f67dc9fb000-7f67dca00000 rw-p 000d4000 08:01 7221                       /opt/ibm/iaccess/lib64/libcwbodbc.so
7f67dca00000-7f67dcc00000 rw-p 00000000 00:00 0 
7f67dccb8000-7f67dccce000 r-xp 00000000 08:01 262160                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7f67dccce000-7f67dcecd000 ---p 00016000 08:01 262160                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7f67dcecd000-7f67dcece000 r--p 00015000 08:01 262160                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7f67dcece000-7f67dcecf000 rw-p 00016000 08:01 262160                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7f67dcecf000-7f67dd041000 r-xp 00000000 08:01 137490                     /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22
7f67dd041000-7f67dd241000 ---p 00172000 08:01 137490                     /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22
7f67dd241000-7f67dd24b000 r--p 00172000 08:01 137490                     /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22
7f67dd24b000-7f67dd24d000 rw-p 0017c000 08:01 137490                     /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22
7f67dd24d000-7f67dd251000 rw-p 00000000 00:00 0 
7f67dd251000-7f67dd25a000 r-xp 00000000 08:01 166610                     /usr/lib/x86_64-linux-gnu/libltdl.so.7.3.1
7f67dd25a000-7f67dd459000 ---p 00009000 08:01 166610                     /usr/lib/x86_64-linux-gnu/libltdl.so.7.3.1
7f67dd459000-7f67dd45a000 r--p 00008000 08:01 166610                     /usr/lib/x86_64-linux-gnu/libltdl.so.7.3.1
7f67dd45a000-7f67dd45b000 rw-p 00009000 08:01 166610                     /usr/lib/x86_64-linux-gnu/libltdl.so.7.3.1
7f67dd45b000-7f67dd480000 r-xp 00000000 08:01 262220                     /lib/x86_64-linux-gnu/liblzma.so.5.2.2
7f67dd480000-7f67dd67f000 ---p 00025000 08:01 262220                     /lib/x86_64-linux-gnu/liblzma.so.5.2.2
7f67dd67f000-7f67dd680000 r--p 00024000 08:01 262220                     /lib/x86_64-linux-gnu/liblzma.so.5.2.2
7f67dd680000-7f67dd681000 rw-p 00025000 08:01 262220                     /lib/x86_64-linux-gnu/liblzma.so.5.2.2
7f67dd681000-7f67dd69a000 r-xp 00000000 08:01 262379                     /lib/x86_64-linux-gnu/libz.so.1.2.8
7f67dd69a000-7f67dd899000 ---p 00019000 08:01 262379                     /lib/x86_64-linux-gnu/libz.so.1.2.8
7f67dd899000-7f67dd89a000 r--p 00018000 08:01 262379                     /lib/x86_64-linux-gnu/libz.so.1.2.8
7f67dd89a000-7f67dd89b000 rw-p 00019000 08:01 262379                     /lib/x86_64-linux-gnu/libz.so.1.2.8
7f67dd89b000-7f67df117000 r-xp 00000000 08:01 143127                     /usr/lib/x86_64-linux-gnu/libicudata.so.57.1
7f67df117000-7f67df316000 ---p 0187c000 08:01 143127                     /usr/lib/x86_64-linux-gnu/libicudata.so.57.1
7f67df316000-7f67df317000 r--p 0187b000 08:01 143127                     /usr/lib/x86_64-linux-gnu/libicudata.so.57.1
7f67df317000-7f67df318000 rw-p 0187c000 08:01 143127                     /usr/lib/x86_64-linux-gnu/libicudata.so.57.1
7f67df318000-7f67df4ac000 r-xp 00000000 08:01 143134                     /usr/lib/x86_64-linux-gnu/libicuuc.so.57.1
7f67df4ac000-7f67df6ab000 ---p 00194000 08:01 143134                     /usr/lib/x86_64-linux-gnu/libicuuc.so.57.1
7f67df6ab000-7f67df6bd000 r--p 00193000 08:01 143134                     /usr/lib/x86_64-linux-gnu/libicuuc.so.57.1
7f67df6bd000-7f67df6be000 rw-p 001a5000 08:01 143134                     /usr/lib/x86_64-linux-gnu/libicuuc.so.57.1
7f67df6be000-7f67df6c0000 rw-p 00000000 00:00 0 
7f67df6c0000-7f67df92b000 r-xp 00000000 08:01 143128                     /usr/lib/x86_64-linux-gnu/libicui18n.so.57.1
7f67df92b000-7f67dfb2b000 ---p 0026b000 08:01 143128                     /usr/lib/x86_64-linux-gnu/libicui18n.so.57.1
7f67dfb2b000-7f67dfb38000 r--p 0026b000 08:01 143128                     /usr/lib/x86_64-linux-gnu/libicui18n.so.57.1
7f67dfb38000-7f67dfb3a000 rw-p 00278000 08:01 143128                     /usr/lib/x86_64-linux-gnu/libicui18n.so.57.1
7f67dfb3a000-7f67dfb3b000 rw-p 00000000 00:00 0 
7f67dfb3b000-7f67dfb53000 r-xp 00000000 08:01 262182                     /lib/x86_64-linux-gnu/libpthread-2.24.so
7f67dfb53000-7f67dfd52000 ---p 00018000 08:01 262182                     /lib/x86_64-linux-gnu/libpthread-2.24.so
7f67dfd52000-7f67dfd53000 r--p 00017000 08:01 262182                     /lib/x86_64-linux-gnu/libpthread-2.24.so
7f67dfd53000-7f67dfd54000 rw-p 00018000 08:01 262182                     /lib/x86_64-linux-gnu/libpthread-2.24.so
7f67dfd54000-7f67dfd58000 rw-p 00000000 00:00 0 
7f67dfd58000-7f67dfeed000 r-xp 00000000 08:01 262166                     /lib/x86_64-linux-gnu/libc-2.24.so
7f67dfeed000-7f67e00ed000 ---p 00195000 08:01 262166                     /lib/x86_64-linux-gnu/libc-2.24.so
7f67e00ed000-7f67e00f1000 r--p 00195000 08:01 262166                     /lib/x86_64-linux-gnu/libc-2.24.so
7f67e00f1000-7f67e00f3000 rw-p 00199000 08:01 262166                     /lib/x86_64-linux-gnu/libc-2.24.so
7f67e00f3000-7f67e00f7000 rw-p 00000000 00:00 0 
7f67e00f7000-7f67e01fa000 r-xp 00000000 08:01 134316                     /usr/lib/x86_64-linux-gnu/libsqlite3.so.0.8.6
7f67e01fa000-7f67e03f9000 ---p 00103000 08:01 134316                     /usr/lib/x86_64-linux-gnu/libsqlite3.so.0.8.6
7f67e03f9000-7f67e03fc000 r--p 00102000 08:01 134316                     /usr/lib/x86_64-linux-gnu/libsqlite3.so.0.8.6
7f67e03fc000-7f67e03fe000 rw-p 00105000 08:01 134316                     /usr/lib/x86_64-linux-gnu/libsqlite3.so.0.8.6
7f67e03fe000-7f67e03ff000 rw-p 00000000 00:00 0 
7f67e03ff000-7f67e0462000 r-xp 00000000 08:01 173833                     /usr/lib/x86_64-linux-gnu/libodbc.so.2.0.0
7f67e0462000-7f67e0661000 ---p 00063000 08:01 173833                     /usr/lib/x86_64-linux-gnu/libodbc.so.2.0.0
7f67e0661000-7f67e0662000 r--p 00062000 08:01 173833                     /usr/lib/x86_64-linux-gnu/libodbc.so.2.0.0
7f67e0662000-7f67e0669000 rw-p 00063000 08:01 173833                     /usr/lib/x86_64-linux-gnu/libodbc.so.2.0.0
7f67e0669000-7f67e066d000 rw-p 00000000 00:00 0 
7f67e066d000-7f67e081d000 r-xp 00000000 08:01 143148                     /usr/lib/x86_64-linux-gnu/libxml2.so.2.9.4
7f67e081d000-7f67e0a1d000 ---p 001b0000 08:01 143148                     /usr/lib/x86_64-linux-gnu/libxml2.so.2.9.4
7f67e0a1d000-7f67e0a25000 r--p 001b0000 08:01 143148                     /usr/lib/x86_64-linux-gnu/libxml2.so.2.9.4
7f67e0a25000-7f67e0a27000 rw-p 001b8000 08:01 143148                     /usr/lib/x86_64-linux-gnu/libxml2.so.2.9.4
7f67e0a27000-7f67e0a28000 rw-p 00000000 00:00 0 
7f67e0a28000-7f67e0a2b000 r-xp 00000000 08:01 262169                     /lib/x86_64-linux-gnu/libdl-2.24.so
7f67e0a2b000-7f67e0c2a000 ---p 00003000 08:01 262169                     /lib/x86_64-linux-gnu/libdl-2.24.so
7f67e0c2a000-7f67e0c2b000 r--p 00002000 08:01 262169                     /lib/x86_64-linux-gnu/libdl-2.24.so
7f67e0c2b000-7f67e0c2c000 rw-p 00003000 08:01 262169                     /lib/x86_64-linux-gnu/libdl-2.24.so
7f67e0c2c000-7f67e0d2f000 r-xp 00000000 08:01 262170                     /lib/x86_64-linux-gnu/libm-2.24.so
7f67e0d2f000-7f67e0f2e000 ---p 00103000 08:01 262170                     /lib/x86_64-linux-gnu/libm-2.24.so
7f67e0f2e000-7f67e0f2f000 r--p 00102000 08:01 262170                     /lib/x86_64-linux-gnu/libm-2.24.so
7f67e0f2f000-7f67e0f30000 rw-p 00103000 08:01 262170                     /lib/x86_64-linux-gnu/libm-2.24.so
7f67e0f30000-7f67e0f32000 r-xp 00000000 08:01 262186                     /lib/x86_64-linux-gnu/libutil-2.24.so
7f67e0f32000-7f67e1131000 ---p 00002000 08:01 262186                     /lib/x86_64-linux-gnu/libutil-2.24.so
7f67e1131000-7f67e1132000 r--p 00001000 08:01 262186                     /lib/x86_64-linux-gnu/libutil-2.24.so
7f67e1132000-7f67e1133000 rw-p 00002000 08:01 262186                     /lib/x86_64-linux-gnu/libutil-2.24.so
7f67e1133000-7f67e113a000 r-xp 00000000 08:01 262184                     /lib/x86_64-linux-gnu/librt-2.24.so
7f67e113a000-7f67e1339000 ---p 00007000 08:01 262184                     /lib/x86_64-linux-gnu/librt-2.24.so
7f67e1339000-7f67e133a000 r--p 00006000 08:01 262184                     /lib/x86_64-linux-gnu/librt-2.24.so
7f67e133a000-7f67e133b000 rw-p 00007000 08:01 262184                     /lib/x86_64-linux-gnu/librt-2.24.so
7f67e133b000-7f67e134f000 r-xp 00000000 08:01 262183                     /lib/x86_64-linux-gnu/libresolv-2.24.so
7f67e134f000-7f67e154e000 ---p 00014000 08:01 262183                     /lib/x86_64-linux-gnu/libresolv-2.24.so
7f67e154e000-7f67e154f000 r--p 00013000 08:01 262183                     /lib/x86_64-linux-gnu/libresolv-2.24.so
7f67e154f000-7f67e1550000 rw-p 00014000 08:01 262183                     /lib/x86_64-linux-gnu/libresolv-2.24.so
7f67e1550000-7f67e1552000 rw-p 00000000 00:00 0 
7f67e1552000-7f67e155a000 r-xp 00000000 08:01 262168                     /lib/x86_64-linux-gnu/libcrypt-2.24.so
7f67e155a000-7f67e175a000 ---p 00008000 08:01 262168                     /lib/x86_64-linux-gnu/libcrypt-2.24.so
7f67e175a000-7f67e175b000 r--p 00008000 08:01 262168                     /lib/x86_64-linux-gnu/libcrypt-2.24.so
7f67e175b000-7f67e175c000 rw-p 00009000 08:01 262168                     /lib/x86_64-linux-gnu/libcrypt-2.24.so
7f67e175c000-7f67e178a000 rw-p 00000000 00:00 0 
7f67e178a000-7f67e17ad000 r-xp 00000000 08:01 262162                     /lib/x86_64-linux-gnu/ld-2.24.so
7f67e18d0000-7f67e1921000 rw-p 00000000 00:00 0 
7f67e1934000-7f67e1943000 r--p 00000000 08:01 6698                       /opt/ibm/iaccess/mri2924/cwbcomsg.dll
7f67e1943000-7f67e194a000 r--s 00000000 08:01 133349                     /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache
7f67e194a000-7f67e19a7000 rw-p 00000000 00:00 0 
7f67e19a8000-7f67e19a9000 rw-p 00000000 00:00 0 
7f67e19a9000-7f67e19ad000 r--p 00000000 08:01 6691                       /opt/ibm/iaccess/mri2924/cwbodmsg.dll
7f67e19ad000-7f67e19ae000 r--p 00023000 08:01 262162                     /lib/x86_64-linux-gnu/ld-2.24.so
7f67e19ae000-7f67e19af000 rw-p 00024000 08:01 262162                     /lib/x86_64-linux-gnu/ld-2.24.so
7f67e19af000-7f67e19b0000 rw-p 00000000 00:00 0 
7ffd69d61000-7ffd69d82000 rw-p 00000000 00:00 0                          [stack]
7ffd69d90000-7ffd69d92000 r--p 00000000 00:00 0                          [vvar]
7ffd69d92000-7ffd69d94000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-03-26 19:41 UTC] calvin at cmpct dot info
GDB:

Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51	../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) where
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1  0x00007ffff63db42a in __GI_abort () at abort.c:89
#2  0x00007ffff6417c00 in __libc_message (do_abort=do_abort@entry=2, fmt=fmt@entry=0x7ffff650cfd0 "*** Error in `%s': %s: 0x%s ***\n") at ../sysdeps/posix/libc_fatal.c:175
#3  0x00007ffff641dfc6 in malloc_printerr (action=3, str=0x7ffff6509b58 "free(): invalid size", ptr=<optimized out>, ar_ptr=<optimized out>) at malloc.c:5049
#4  0x00007ffff641e80e in _int_free (av=0x7ffff6740b00 <main_arena>, p=0x7ffff30792f0, have_lock=0) at malloc.c:3905
#5  0x000055555580ae35 in dbh_free (dbh=0x5555568e67d0, free_persistent=true) at /home/calvin/php-src/ext/pdo/pdo_dbh.c:1450
#6  0x000055555580b231 in php_pdo_pdbh_dtor (res=0x555556907360) at /home/calvin/php-src/ext/pdo/pdo_dbh.c:1514
#7  0x0000555555a88235 in plist_entry_destructor (zv=0x7fffffffe2f0) at /home/calvin/php-src/Zend/zend_list.c:195
#8  0x0000555555a83231 in _zend_hash_del_el_ex (ht=0x555556772e88 <executor_globals+616>, idx=0, p=0x5555568fdff0, prev=0x0) at /home/calvin/php-src/Zend/zend_hash.c:1352
#9  0x0000555555a832fd in _zend_hash_del_el (ht=0x555556772e88 <executor_globals+616>, idx=0, p=0x5555568fdff0) at /home/calvin/php-src/Zend/zend_hash.c:1375
#10 0x0000555555a84b18 in zend_hash_graceful_reverse_destroy (ht=0x555556772e88 <executor_globals+616>) at /home/calvin/php-src/Zend/zend_hash.c:1829
#11 0x0000555555a88347 in zend_destroy_rsrc_list (ht=0x555556772e88 <executor_globals+616>) at /home/calvin/php-src/Zend/zend_list.c:228
#12 0x0000555555a6b8d7 in zend_shutdown () at /home/calvin/php-src/Zend/zend.c:1087
#13 0x00005555559d7257 in php_module_shutdown () at /home/calvin/php-src/main/main.c:2371
#14 0x0000555555bc0c3b in main (argc=2, argv=0x55555678b670) at /home/calvin/php-src/sapi/cli/php_cli.c:1387
 [2021-03-30 17:54 UTC] cmb@php.net
FWIW, I cannot reproduce this on Windows (SQLServer).
 [2021-03-30 18:24 UTC] calvin at cmpct dot info
Let me know if you need access to a system/the driver. I wonder if this is a possible IBM driver bug and PHP is taking the blame here, but it's odd I can only repro on Linux if so.
 [2021-05-04 20:16 UTC] calvin at cmpct dot info
Just FWIW, I can reproduce this issue on Fedora  with MariaDB's ODBC driver, and with all other drivers disabled in odbcinst.ini. I don't think this is an ODBC driver issue as a result.
 [2021-05-04 22:48 UTC] calvin at cmpct dot info
I'm poking this in GDB and I think it's the connection string (or a chunk of it) that's getting leaked. Transcript from my session: https://gist.githubusercontent.com/NattyNarwhal/69359a88979e254b6f9eb9e91512c522/raw/ddeed94e65f4401092b9ba8586dfc883b9c44fd0/gistfile1.txt
 [2022-02-15 15:07 UTC] calvin at cmpct dot info
FWIW, I can still reproduce this on 8.2 master (b582427ff53db38cac3e23d3c990814da418038c), but I think the symptom might have changed.

Test program using MariaDB's ODBC driver (so we can discount IBM's weird driver), running on Fedora 35:

```
<?php

$connection = new PDO('odbc:Driver=MariaDB;Database=<DB here>', 'username', 'password', array(PDO::ATTR_PERSISTENT => true));

```

Gets:

```
$ /tmp/php/bin/php ../test-pdo-odbc-mariadb.php 
[Tue Feb 15 11:04:47 2022]  Script:  '/home/calvin/src/test-pdo-odbc-mariadb.php'
/home/calvin/src/php-src/Zend/zend_smart_str.c(164) :  Freeing 0x00007f2daa285300 (224 bytes), script=/home/calvin/src/test-pdo-odbc-mariadb.php
=== Total 1 memory leaks detected ===
munmap_chunk(): invalid pointer
Aborted (core dumped)
```

The address of the leaked pointer changes, and it only leaks if the connection is successful; it will always crash with munmap_chunk() regardless. USE_ZEND_ALLOC=0 seems to make it work, but probably by covering it up.
 [2022-02-15 15:17 UTC] calvin at cmpct dot info
I can confirm it's the constructed connection string (if you supply UID/PWD as args for the PDO ctor instead of on the connection string itself) that's leaking:

```
(gdb) break main.c:1604
Breakpoint 1 at 0x965f35: file /home/calvin/src/php-src/main/main.c, line 1604.
(gdb) run
Starting program: /tmp/php/bin/php ../test-pdo-odbc-mariadb.php

This GDB supports auto-downloading debuginfo from the following URLs:
https://debuginfod.fedoraproject.org/ 
Enable debuginfod for this session? (y or [n]) y
Debuginfod has been enabled.
To make this setting permanent, add 'set debuginfod enabled on' to .gdbinit.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
[Tue Feb 15 11:15:16 2022]  Script:  '/home/calvin/src/test-pdo-odbc-mariadb.php'

Breakpoint 1, php_message_handler_for_zend (message=4, data=0x7fffffffbe70) at /home/calvin/src/php-src/main/main.c:1604
1604						snprintf(memory_leak_buf, 512, "%s(%" PRIu32 ") :  Freeing " ZEND_ADDR_FMT " (%zu bytes), script=%s\n", t->filename, t->lineno, (size_t)t->addr, t->size, SAFE_FILENAME(SG(request_info).path_translated));
(gdb) p t
$1 = (zend_leak_info *) 0x7fffffffbe70
(gdb) p *t
$2 = {addr = 0x7ffff7685300, size = 224, filename = 0x14bf478 "/home/calvin/src/php-src/Zend/zend_smart_str.c", orig_filename = 0x0, lineno = 164, orig_lineno = 0}
(gdb) p (char*)0x7ffff7685300
$3 = 0x7ffff7685300 "Driver=MariaDB;Database=<database>;UID=<UID>;PWD=<Password>"
```
 [2022-02-15 16:27 UTC] calvin at cmpct dot info
I think I have enough to explain how this happens:

1. PDO constructs a new connection string with spprintf, replaces and frees the old one
2. When dbh_free is called, the refcount is 2, but it hits the persistent connection early return, presumably for reuse

```
Breakpoint 2, dbh_free (dbh=0x186e180, free_persistent=false) at /home/calvin/src/php-src/ext/pdo/pdo_dbh.c:1432
1432		if (dbh->query_stmt) {
(gdb) p *dbh
$4 = {methods = 0x13707c0 <odbc_methods>, driver_data = 0x18ce950, username = 0x199e6b0 "lobsters", password = 0x19a5480 "password", is_persistent = 1, auto_commit = 1, is_closed = 0, alloc_own_columns = 1, in_txn = false, 
  max_escaped_char_length = 0, oracle_nulls = 0, stringify = 0, skip_param_evt = 0, _reserved_flags = 0, data_source = 0x7ffff7685300 "Driver=MariaDB;Database=lobsters_dev;UID=lobsters;PWD=password", data_source_len = 36, 
  error_code = "00000", error_mode = PDO_ERRMODE_EXCEPTION, native_case = PDO_CASE_NATURAL, desired_case = PDO_CASE_NATURAL, persistent_id = 0x19a5400 "PDO:DBH:DSN=odbc:Driver=MariaDB;Database=lobsters_dev:lobsters:password", 
  persistent_id_len = 71, refcount = 2, cls_methods = {0x0, 0x0}, driver = 0x1370920 <pdo_odbc_driver>, def_stmt_ce = 0x194b610, def_stmt_ctor_args = {value = {lval = 0, dval = 0, counted = 0x0, str = 0x0, arr = 0x0, obj = 0x0, 
      res = 0x0, ref = 0x0, ast = 0x0, zv = 0x0, ptr = 0x0, ce = 0x0, func = 0x0, ww = {w1 = 0, w2 = 0}}, u1 = {type_info = 0, v = {type = 0 '\000', type_flags = 0 '\000', u = {extra = 0}}}, u2 = {next = 0, cache_slot = 0, 
      opline_num = 0, lineno = 0, num_args = 0, fe_pos = 0, fe_iter_idx = 0, property_guard = 0, constant_flags = 0, extra = 0}}, query_stmt = 0x0, query_stmt_zval = {value = {lval = 0, dval = 0, counted = 0x0, str = 0x0, arr = 0x0, 
      obj = 0x0, res = 0x0, ref = 0x0, ast = 0x0, zv = 0x0, ptr = 0x0, ce = 0x0, func = 0x0, ww = {w1 = 0, w2 = 0}}, u1 = {type_info = 0, v = {type = 0 '\000', type_flags = 0 '\000', u = {extra = 0}}}, u2 = {next = 0, cache_slot = 0, 
      opline_num = 0, lineno = 0, num_args = 0, fe_pos = 0, fe_iter_idx = 0, property_guard = 0, constant_flags = 0, extra = 0}}, default_fetch_type = PDO_FETCH_BOTH}
(gdb) p dbh->refcount
$5 = 2
(gdb) p free_persistent
$6 = false
(gdb) next
1437		if (dbh->is_persistent) {
(gdb) next
1439			ZEND_ASSERT(!free_persistent || (dbh->refcount == 1));
(gdb) next
1441			if (!free_persistent && (--dbh->refcount)) {
(gdb) next
1442				return;
(gdb) p free_persistent
$7 = false
(gdb) p dbh->refcount
$8 = 1

```

This means the pefree for dbh->data_source never gets called when we want it to.

3. But this is CLI, so we're exiting anyways. It seems the PDO object is freed during the check for leaks, and the crash happens here inside of glibc (mixed up allocator? double free?)

```
Starting program: /tmp/php/bin/php ../test-pdo-odbc-mariadb.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
[Tue Feb 15 12:06:10 2022]  Script:  '/home/calvin/src/test-pdo-odbc-mariadb.php'
/home/calvin/src/php-src/Zend/zend_smart_str.c(164) :  Freeing 0x00007ffff7685300 (224 bytes), script=/home/calvin/src/test-pdo-odbc-mariadb.php
=== Total 1 memory leaks detected ===

Breakpoint 1, dbh_free (dbh=0x186e180, free_persistent=true) at /home/calvin/src/php-src/ext/pdo/pdo_dbh.c:1451
1451			pefree((char *)dbh->data_source, dbh->is_persistent);
(gdb) step
__GI___libc_free (mem=0x7ffff7685300) at malloc.c:3240
Downloading -0.00 MB source file /usr/src/debug/glibc-2.34-25.fc35.x86_64/malloc/malloc.c
3240    {                                                                                                                                                                                                                                    
(gdb) step
3244	  if (mem == 0)                              /* free(0) has no effect */
(gdb) step
3252	  int err = errno;
(gdb) step
3256	  if (chunk_is_mmapped (p))                       /* release mmapped memory. */
(gdb) step
3260	      if (!mp_.no_dyn_threshold
(gdb) step
3269	      munmap_chunk (p);
(gdb) step
munmap_chunk (p=0x7ffff76852f0) at malloc.c:2935
2935	  size_t pagesize = GLRO (dl_pagesize);
(gdb) next
2936	  INTERNAL_SIZE_T size = chunksize (p);
(gdb) next
2938	  assert (chunk_is_mmapped (p));
(gdb) next
2941	  uintptr_t block = (uintptr_t) p - prev_size (p);
(gdb) next
2942	  size_t total_size = prev_size (p) + size;
(gdb) next
2948	  if (__glibc_unlikely ((block | total_size) & (pagesize - 1)) != 0
(gdb) next
2950	    malloc_printerr ("munmap_chunk(): invalid pointer");
(gdb) next
munmap_chunk(): invalid pointer
```
 [2022-02-21 11:47 UTC] git@php.net
Automatic comment on behalf of NattyNarwhal (author) and cmb69 (committer)
Revision: https://github.com/php/php-src/commit/dfd2a80b69d469d879d60c12c1d9d9ca49cb3f76
Log: Fix #80909: crash with persistent connections in PDO_ODBC
 [2022-02-21 11:47 UTC] git@php.net
-Status: Open +Status: Closed
 [2022-02-21 11:49 UTC] cmb@php.net
-Assigned To: +Assigned To: cmb
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 12:01:31 2024 UTC