У нас есть устаревшее веб-приложение для Windows, которое использует Microsoft SQL Server 2005. Два года назад мы переписали часть этого приложения с использованием PHP и ODBC в 32-битной виртуализированной системе Debian. Это приложение работает нормально (примерно один запрос 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 ()» и текст после него никогда не отображаются.
Я отлаживал файл PHP, вызывая его напрямую через php5 (пакет php5-cli). На этот раз он действительно получает данные из базы данных (текущий номер редакции, который меняется каждую неделю). Но после вывода я получаю строку сообщения об ошибке
ALERT - canary mismatch on efree() - heap overflow detected (attacker 'REMOTE_ADDR not set', file 'unknown')
Вы должны знать, что Debian PHP5 интегрирован с патчем Suhosin. Похоже, он обнаруживает повреждение памяти в odbc_fetch_object ().
Мы попытались выполнить отладку с помощью valgrind с подавленным выделением памяти 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
Можете ли вы посоветовать обходной путь для того, что кажется ошибкой выделения памяти в библиотеке libtdsodbc.so? Или у вас есть идея, что мы можем сделать, кроме как получить исходный код и исправить ошибку самостоятельно?
Хм, похоже, в драйвере PHP odbc больше 64-битных ошибок. Я сообщил эта ошибка в redhat несколько лет назад; это было для PHP 4.3.x на RHEL4, и тогда он был уже исправлен в апстриме, так что, по-видимому, у Debian Lenny уже есть исправленная версия.
Кроме того, чтобы исправить это самостоятельно или, по крайней мере, отправить отчеты об ошибках вверх по течению и в то же время не использовать php-odbc на 64-битных платформах, у меня нет лучшего совета. Сожалею.
EDIT: вы можете попробовать вообще не использовать ODBC, а напрямую использовать интерфейс TDS. Хотя я не уверен, существует ли интерфейс TDS уровня PHP, но вы можете сделать это, по крайней мере, если вы используете интерфейс базы данных PHP PDO, который доступен в PHP 5.x. См. Модуль PDO_DBLIB.
Ошибка отсутствует в PHP 5.2.7, потому что они изменили len с SDWORD на правильный тип SQLLEN, который является 64-битным для 64-битных платформ.
С уважением, Фредиано Зильо (он же freddy77)
Я отправил электронное письмо трем разработчикам на адрес http://freetds.org, отправил отчет об ошибке на PHP http://bugs.php.net/bug.php?id=50370 и в Debian (номер будет опубликован позже).
Для нас уже слишком поздно. Мы собираемся отменить этот проект, но я надеюсь, что разработчики смогут исправить ошибку, чтобы другие не были остановлены так жестоко, как мы.