We have a legacy Windows web application which uses Microsoft SQL Server 2005. Two years ago we rewrote a part of this application using PHP and ODBC on a 32 bit virtualized Debian system. This application works okay (about one SQL request of thousand produces bogus data, but this is handled by the application). Debian packages used are: php5-odbc, odbcinst1debian1, tdsodbc, unixodbc, freetds-common.
Now we want to unvirtualize this and install the application as an Apache virtual host on a 64 bit Debian Lenny system. But something bad happens in the PHP function odbc_fetch_object(). I have
echo "Before odbc_fetch_object(); $query\n"; flush();
if ($query) $row = odbc_fetch_object($query);
echo "After odbc_fetch_object();\n"; flush();
echo "Edition number $row->Id\n";
but the text "After odbc_fetch_object()" and text following it are never shown.
I debugged the PHP file by calling it by php5 directly (package php5-cli). This time it really gets data from the database (the current edition number which changes every week). But after the output I get the error message string
ALERT - canary mismatch on efree() - heap overflow detected (attacker 'REMOTE_ADDR not set', file 'unknown')
You should know that Debian PHP5 is integrated with the Suhosin patch. It seems that it discovers memory corruption in odbc_fetch_object().
We tried to debug with valgrind with suppressed Zend memory allocation:
USE_ZEND_ALLOC=0 valgrind --leak-check=full ./current.php
and got following output:
==3831== Memcheck, a memory error detector.
==3831== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==3831== Using LibVEX rev 1854, a library for dynamic binary translation.
==3831== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==3831== Using valgrind-3.3.1-Debian, a dynamic binary instrumentation framework.
==3831== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==3831== For more details, rerun with: -v
==3831==
==3831== Invalid write of size 8
==3831== at 0xD64420C: (within /usr/lib/odbc/libtdsodbc.so)
==3831== by 0xB55E859: SQLColAttributes (in /usr/lib/libodbc.so.1.0.0)
==3831== by 0xB34AA37: odbc_bindcols (in /usr/lib/php5/20060613/odbc.so)
==3831== by 0xB350B86: zif_odbc_exec (in /usr/lib/php5/20060613/odbc.so)
==3831== by 0xBDEDC9C: (within /usr/lib/php5/20060613/suhosin.so)
==3831== by 0x6A5798: (within /usr/bin/php5)
==3831== by 0x691003: execute (in /usr/bin/php5)
==3831== by 0xBDEE125: (within /usr/lib/php5/20060613/suhosin.so)
==3831== by 0x66CDF7: zend_execute_scripts (in /usr/bin/php5)
==3831== by 0x627667: php_execute_script (in /usr/bin/php5)
==3831== by 0x6EBFF6: main (in /usr/bin/php5)
==3831== Address 0xd2b564c is 44 bytes inside a block of size 48 alloc'd
==3831== at 0x4C2260E: malloc (vg_replace_malloc.c:207)
==3831== by 0xB34A911: odbc_bindcols (in /usr/lib/php5/20060613/odbc.so)
==3831== by 0xB350B86: zif_odbc_exec (in /usr/lib/php5/20060613/odbc.so)
==3831== by 0xBDEDC9C: (within /usr/lib/php5/20060613/suhosin.so)
==3831== by 0x6A5798: (within /usr/bin/php5)
==3831== by 0x691003: execute (in /usr/bin/php5)
==3831== by 0xBDEE125: (within /usr/lib/php5/20060613/suhosin.so)
==3831== by 0x66CDF7: zend_execute_scripts (in /usr/bin/php5)
==3831== by 0x627667: php_execute_script (in /usr/bin/php5)
==3831== by 0x6EBFF6: main (in /usr/bin/php5)
Before odbc_fetch_object(): Resource id #6
After odbc_fetch_object()
Edition number 547
Some static text
==3831==
==3831== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 531 from 4)
==3831== malloc/free: in use at exit: 58,755 bytes in 1,558 blocks.
==3831== malloc/free: 22,559 allocs, 21,001 frees, 3,867,219 bytes allocated.
==3831== For counts of detected errors, rerun with: -v
==3831== searching for pointers to 1,558 not-freed blocks.
==3831== checked 1,223,080 bytes.
==3831==
==3831==
==3831== 2 bytes in 1 blocks are definitely lost in loss record 1 of 24
==3831== at 0x4C2260E: malloc (vg_replace_malloc.c:207)
==3831== by 0x7609D91: strdup (in /lib/libc-2.7.so)
==3831== by 0xBDDF74B: ???
==3831== by 0x68199D: zend_register_ini_entries (in /usr/bin/php5)
==3831== by 0xBDDFBCF: ???
==3831== by 0x6732DA: zend_startup_module_ex (in /usr/bin/php5)
==3831== by 0x67828A: zend_hash_apply (in /usr/bin/php5)
==3831== by 0x671B59: zend_startup_modules (in /usr/bin/php5)
==3831== by 0x628E22: php_module_startup (in /usr/bin/php5)
==3831== by 0x6EA71C: (within /usr/bin/php5)
==3831== by 0x6EAF31: main (in /usr/bin/php5)
==3831==
==3831==
==3831== 292 (52 direct, 240 indirect) bytes in 1 blocks are definitely lost in loss record 11 of 24
==3831== at 0x4C2260E: malloc (vg_replace_malloc.c:207)
==3831== by 0x766D52F: (within /lib/libc-2.7.so)
==3831== by 0x766DD06: __nss_database_lookup (in /lib/libc-2.7.so)
==3831== by 0xCC2631F: ???
==3831== by 0xCC2702C: ???
==3831== by 0x762C101: getpwuid_r (in /lib/libc-2.7.so)
==3831== by 0x762B9CE: getpwuid (in /lib/libc-2.7.so)
==3831== by 0xB59C2EF: ???
==3831== by 0xB599B2B: ???
==3831== by 0xB58A013: ???
==3831== by 0xB56307F: ???
==3831== by 0xB34896D: ???
==3831==
==3831==
==3831== 512 bytes in 1 blocks are definitely lost in loss record 17 of 24
==3831== at 0x4C22741: realloc (vg_replace_malloc.c:429)
==3831== by 0x678AC8: (within /usr/bin/php5)
==3831== by 0x678B44: (within /usr/bin/php5)
==3831== by 0x67AEF7: _zend_hash_add_or_update (in /usr/bin/php5)
==3831== by 0xBDED02C: ???
==3831== by 0xBDDE995: ???
==3831== by 0x677690: (within /usr/bin/php5)
==3831== by 0x6634B1: zend_llist_apply_with_del (in /usr/bin/php5)
==3831== by 0x677676: zend_startup_extensions (in /usr/bin/php5)
==3831== by 0x628E5B: php_module_startup (in /usr/bin/php5)
==3831== by 0x6EA71C: (within /usr/bin/php5)
==3831== by 0x6EAF31: main (in /usr/bin/php5)
==3831==
==3831== LEAK SUMMARY:
==3831== definitely lost: 566 bytes in 3 blocks.
==3831== indirectly lost: 240 bytes in 10 blocks.
==3831== possibly lost: 0 bytes in 0 blocks.
==3831== still reachable: 57,949 bytes in 1,545 blocks.
==3831== suppressed: 0 bytes in 0 blocks.
==3831== Reachable blocks (those to which a pointer was found) are not shown.
==3831== To see them, rerun with: --leak-check=full --show-reachable=yes
Can you advise a workaround for something that seems to be a memory allocation bug in the library libtdsodbc.so? Or do you have an idea what could we do except getting the source code and fixing the bug ourselves?