Bug #81688 [Com]: PDO_ODBC doesn't handle fixed-length character columns with character conversio

From: Date: Tue, 28 Dec 2021 16:58:01 +0000
Subject: Bug #81688 [Com]: PDO_ODBC doesn't handle fixed-length character columns with character conversio
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-238606@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=81688&edit=1 ID: 81688 Comment by: calvin at cmpct dot info Reported by: calvin at cmpct dot info Summary: PDO_ODBC doesn't handle fixed-length character columns with character conversio Status: Assigned Type: Bug Package: PDO ODBC Operating System: IBM i 7.2 PHP Version: 8.0.13 Assigned To: cmb Block user comment: N Private report: N New Comment: Was going to write a sample w/ ODBC in C, but decided to poke the existing code path to determine if it's just junk left over before, or just created after. Gist b/c it's too long to post here: https://gist.githubusercontent.com/NattyNarwhal/3864224066dda8ed4be991c06e67a670/raw/3e3aad9efbc6472f7dde1e8e1167e2bc9ad06288/gistfile1.txt (I rebuilt PHP w/ --enable-debug for my own sanity in GDB. Also on Linux too.) Note that the garbage on 0x7ffff767e3a8 that appears in the string comes from before the memset, so I think this is just leftover in memory and not coming from the driver. (You can also see my connection string... thankfully not my password.) Previous Comments: ------------------------------------------------------------------------ [2021-12-27 22:10:27] cmb@php.net > […], just chuffed at the issue tracker that it got auto-closed. Yeah, that is a bit unfortunate. If the status is set to "feedback", the bug is automatically closed on the next but one Sunday, even if feedback has been provided. You, as bug reporter, should be able to change the status back to "open", though ("re-opened" doesn't work, IIRC). > but I don't notice any different behaviour Hmm, does the *driver* fill the buffers with some garbage at the end, in this case? I'll have a closer look tomorrow; it seems using SQLGetData() always (for testing purposes) might be a way to proceed. ------------------------------------------------------------------------ [2021-12-27 21:32:34] calvin at cmpct dot info Thankfully was a quick build, but I don't notice any different behaviour (where /tmp/php is a build of PHP-8.0.14 with your patch vs. my system 8.0.13 from Fedora, both using the Linux build of the same driver I've been using on i): ``` [calvin@salient src]$ /tmp/php/bin/php -d extension_dir=/tmp/php/lib/php/extensions/no-debug-non-zts-20200930 test4.php before ODBC bool(true) after ODBC Record string(180) "éééééééééééééééééééééééééééééé V��(���j" Record string(165) "ééééééééééééééé " Record string(155) "ééééé " [calvin@salient src]$ php test4.php before ODBC bool(true) after ODBC Record string(180) "éééééééééééééééééééééééééééééé �c��]" Record string(165) "ééééééééééééééé �c��]" Record string(155) "ééééé " ``` ------------------------------------------------------------------------ [2021-12-27 21:16:32] calvin at cmpct dot info Testing your patch and it faults, but it segfaults on the additional memset. Bizarre, so I'm gonna check if it reproduces the same on Linux. ``` (gdb) run Starting program: /QOpenSys/pkgs/bin/php -d error_log= test4.php [New Thread 1] before ODBC bool(true) after ODBC Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 1] 0x000000000000000c in ?? () (gdb) sharedlib odbc Reading symbols from /QOpenSys/pkgs/lib/libodbcinst.so.2(shr_64.o)...done. Reading symbols from /QOpenSys/pkgs/lib/libcwbodbc.so...done. Reading symbols from /QOpenSys/pkgs/lib/php-8.0/extensions/pdo_odbc.so...done. Reading symbols from /QOpenSys/pkgs/lib/libodbc.so.2(shr_64.o)...done. Reading symbols from /QOpenSys/pkgs/lib/php-8.0/extensions/odbc.so...done. (gdb) where #0 0x000000000000000c in ?? () #1 0x090000004e2862d0 in php_odbc_fetch_hash.isra.11.constprop () from /QOpenSys/pkgs/lib/php-8.0/extensions/odbc.so #2 0x00000001000b9914 in execute_ex (ex=0x70000000022ffe0) at /home/calvin/rpmbuild/BUILD/php-8.0.14/Zend/zend_execute.c:51782 #3 0x00000001000c1f30 in zend_execute (op_array=0x70000000022ffe0, return_value=0x7) at /home/calvin/rpmbuild/BUILD/php-8.0.14/Zend/zend_execute.c:58537 #4 0x00000001000e5b80 in zend_execute_scripts (type=2293728, retval=0x7, file_count=0) at /home/calvin/rpmbuild/BUILD/php-8.0.14/Zend/zend.c:1680 #5 0x00000001001d1ff4 in php_execute_script (primary_file=0xfffffffffffdec0) at /home/calvin/rpmbuild/BUILD/php-8.0.14/main/main.c:2539 #6 0x0000000100002d00 in do_cli (argc=4, argv=0x1800ee770) at /home/calvin/rpmbuild/BUILD/php-8.0.14/sapi/cli/php_cli.c:347 #7 0x00000001000008cc in main (argc=4, argv=0x7) at /home/calvin/rpmbuild/BUILD/php-8.0.14/sapi/cli/php_cli.c:1337 ``` ------------------------------------------------------------------------ [2021-12-27 19:42:10] calvin at cmpct dot info Hi Christoph, I'll give this patch a shot (and see if Db2 has that column type...). I'm fine with the late reply considering the season (time off is more important than ODBC bugs), just chuffed at the issue tracker that it got auto-closed. ------------------------------------------------------------------------ [2021-12-27 16:51:04] cmb@php.net Sorry for the late reply! From what I can tell, there may be two different issues here: (a) PHP does not allocate sufficient space for the data, and (b) the driver may deliver fewer data than PHP expects, resulting in arbitrary memory contents to be given to userland. Let's focus on (b) for now, since that should be easy to fix by zeroing the buffers before fetching. Could you please try the following patch for ODBC (PDO_ODBC could likely get a similar fix): ext/odbc/php_odbc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index d4de4ec75b..d0ee19aa07 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -1381,6 +1381,12 @@ static void php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type) RETURN_FALSE; } + for (i = 0; i < result->numcols; i++) { + if (result->values[i].value != NULL) { + memset(result->values[i].value, 0, result->values[i].vallen); + } + } + #ifdef HAVE_SQL_EXTENDED_FETCH if (result->fetch_abs) { if (rownum > 0) { Something else that may be worth investigating is the usage of SQL_LONGVARCHAR columns (or respective casts), if something like that is supported by the DB and the driver. Such columns are not bound, but rather SQLGetData() is used to retrieve the data, and the driver is supposed to report the length of the transferred data in the StrLen_or_IndPtr argument (so in this case neither SQLDescribeCol() nor SQLColAttribute() are used to compute the length). ------------------------------------------------------------------------ The remainder of the comments for this report are too long. To view the rest of the comments, please view the bug report online at https://bugs.php.net/bug.php?id=81688 -- Edit this bug report at https://bugs.php.net/bug.php?id=81688&edit=1

« previous php.bugs (#238606) next »