Motto

В тихом саду здравомыслия
Пусть на вас постоянно падают
кокосовые орехи пробужденности.
Чогьям Трунгпа РИНПОЧЕ


Версия для мобильного


среда, 28 апреля 2010 г.

Текучка 11: Поиск AV в полевых условиях и найденная в результате цепочка ужасного кода.

Недавно был случай: у клиента при запуске программы возник загадочный Access Violation, а проблема оказалась в статически прилинкованной Dll-ке. Но начав исследовать эту проблему, выявился большой комок ужасного кода.

Звонит коллега: я у клиента, поставил обновление, и последний билд не запускается на 3х компах из 10. При старте программы вылетает сообщение об ошибке по адресу 0x0000L0L0. А очень старый билд запускается без проблем. Подключись пожалуйста удалённо, говорит, и посмотри в чём может быть дело.

Дело осложнялось тем, что даже при запуске проги в режиме отладки log оставался пустым. Значит ошибка происходила до запуска системы логирования, скорее всего в initialization секции какого-то юнита. Расставил во всех initialization секциях основных модулей показ диалогов с сообщениями, чтобы понять в чём проблема. Сделал билд, подключился. Запускаю - тот же эффект, моих сообщений нет, сразу же Access Violation.

Решил посмотреть при обращении к каким файлам происходит сбой. Скачал и запустил Process Monitor. Программа вылетает после обращения к gds32.dll (клиентская библиотека Firebird). Dll-ка лежит рядом с exe, версия последняя - всё как надо.

Ещё раз сам проверяю очень старый билд - тот запускается без проблем.

А тут надо заметить, что очень старый билд лежал в папке c:\MyProgram, а новый билд был в папке c:\MyProgram\NewBuild. Названия папок конечно были другие, но иерархия та же. Скопировал я exe от очень старого билда в папку к новому, и опа - тоже вылетает. А если последний билд перенести в c:\MyProgram то он запускается нормально. А когда-то, после пары случаев поиска неисправной DLL-ки я добавил в программу возможность посмотреть пути до всех используемых файлов и их версий (dll-ок, конфигов и т.п.). Выяснилось, что при запуске из c:\MyProgram используется gds32.dll версии 0.9, и с ним всё работает. А если брать последнюю gds32 - то ошибка. Знатоки Firebird тут воскликнут, а клиент Firebird был установлен? И будут трижды правы, клиента никто не ставил, новую gds32.dll просто скопировали.

В общем, проблема решилась после установки Microsoft Visual C++ Redistributable Package. Видимо последний клиент использовал более новую версию MSVCRP.

Коллега сказал спасибо, и я стал думать почему так произошло. В программе используются FibPlus и IBX компоненты. Fib-ы насколько я помню, загружают клиента БД динамически, а вот насчёт IBX-ов я не был уверен. Проверил, оказалось что и Fib-ы и IBX-ы тут не причём. Поискал у себя в программе - и обнаружил 2 external функции, ссылающиеся на gds32.dll в самой программе, и ещё целый юнит в отдельном пэкэдже, статически привязывающий кучу функций из gds32.dll. Я не знаю кто был тот программист, который писал этот юнит, как и не знаю то зачем он это делал, но видимо человек решил написать свою собственную прослойку для работы с БД. Часть из этих функций вызывалась из потоков, и при проверке генерировала свои собственные ошибки. В старых версиях FB клиента для каждого потока нужно было создавать отдельный коннект а БД, а те потоки пытались использовать один. В клиенте от версии 2.5, эта часть вроде переделана. В общем, чем разбираться в Firebird API, я решил переписать код потоков на использования компонентов (были выбраны IBX-ы, так как имеющаяся у меня версия FIB-ов имела свои проблемы с мнопоточностью. Я уже сталкивался с этим при написании тестировщика UDF-ок).

В общем, несмотря на то, что у клиента эта ошибка была устранена в течение часа, работа над кодом, не допускающим повторного возникновения той же ошибки затянулась на большее время. Часть статически прилинкованных функций была переписана для использования динамической загрузки. Часть кода, используемая в потоках была переписана ч использованием IBX-ов. А другая часть функций, как выяснилось вообще нигде не использовалась и была удалена.


Спонсор поста:

Агентство интернет-рекламы "Идеал" предоставляет следующие услуги: разработка и продвижение сайта, а также различные виды рекламы.

5 комментариев:

  1. ля такого тестировщика UDF-ок вроде вообще не нужны Data-aware компоненты на формах.

    Почему бы просто не использовать UIB ? :-)

    http://www.progdigy.com/?page_id=5

    ОтветитьУдалить
  2. На формах не нужны, но ведь как-то же с базой данных нужно связываться. =)
    UIB не используются ни в одном из моих проектов, и мне не хотелось добавлять новые компоненты только ради одного тестировщика, тем более что IBX-ы вполне прилично работают в многопоточном окружении.

    Кстати, UIB сейчас включены в состав JVCL.

    ОтветитьУдалить
  3. >> При старте программы вылетает сообщение об ошибке по адресу 0x0000L0L0

    Может я чего и не понял, но как можеть быть такой адрес?

    ОтветитьУдалить
  4. >> При старте программы вылетает сообщение об ошибке по адресу 0x0000L0L0
    > Может я чего и не понял, но как можеть быть такой адрес

    Не может быть такого адреса. Это просто набор символов. Типа шутка такая. =) Реального текста ошибки и адреса я не помню.

    ОтветитьУдалить
  5. :D Я то думал, что отстаю от современных технологий ))) Шучу конечно )

    ОтветитьУдалить

Постоянные читатели