64位UnixODBC和FreeTDS:libtdsodbc.so中的错误?

我们有一个传统的使用Microsoft SQL Server 2005的Windows Web应用程序。两年前,我们在32位虚拟化的Debian系统上使用PHP和ODBC重写了这个应用程序的一部分。 这个应用程序工作正常(关于一千个SQL请求产生假数据,但这是由应用程序处理)。 使用的Debian软件包有:php5-odbc,odbcinst1debian1,tdsodbc,unixodbc,freetds-common。

现在我们想要将这个应用程序作为一个Apache虚拟主机在64位Debian Lenny系统上进行解压缩并安装。 但是在PHP函数odbc_fetch_object()中发生了一些不好的事情。 我有

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"; 

但文本“之后odbc_fetch_object()”和其后的文本从不显示。

我通过直接调用php5来debuggingPHP文件(包php5-cli)。 这次它真的从数据库获取数据(每周更新的当前版本号)。 但在输出后,我得到错误消息string

 ALERT - canary mismatch on efree() - heap overflow detected (attacker 'REMOTE_ADDR not set', file 'unknown') 

您应该知道Debian PHP5与Suhosin补丁集成在一起。 它似乎发现odbc_fetch_object()中的内存损坏。

我们尝试使用valgrind进行debugging,禁止Zend内存分配:

 USE_ZEND_ALLOC=0 valgrind --leak-check=full ./current.php 

并得到以下输出:

 ==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 

你能build议一个解决方法,似乎是库libtdsodbc.so中的内存分配错误? 或者你有一个想法,除了获取源代码和自行修复错误,我们可以做些什么?

嗯,似乎PHP odbc驱动程序中有更多的64位错误。 几年前,我把这个bug报告给redhat。 那是在RHEL4上的PHP 4.3.x版本,当时它已经是固定的上游了,所以大概Debian Lenny已经有了固定的版本。

除了自己修复它,或者至less在上游提交bug报告,同时在64位平台上不使用php-odbc,我没有更好的build议。 抱歉。

编辑:你可以尝试的一件事是,根本不使用ODBC,而是直接使用TDS接口。 虽然我不确定是否存在PHP级别的TDS接口,但是至less可以使用PHP 5.x中提供的PHP PDO数据库接口。 请参阅PDO_DBLIB模块。

我通过电子邮件向http://freetds.org的三位开发人员发送邮件,在PHP http://bugs.php.net/bug.php?id=50370和Debian上提交了一个错误报告(稍后将发布该数字)。

对我们来说太晚了。 我们将取消这个项目,但是我希望开发者能够修复这个bug,这样别人就不会像我们这样残忍地被阻止。

在PHP 5.2.7中不存在的错误导致它们将SDWORD中的len更改为对于64位平台为64位的正确的SQLLENtypes。

问候Frediano Ziglio(又名freddy77)