bash.im ithappens.me zadolba.li
9374

Цена «вопроса»

Одно дело, когда проблемы с совместимостью возникают между разными программами или между разными версиями одной и той же программы. А как насчёт проблем с совместимостью между двумя программами из одного и того же пакета ПО?

Писал я программу свою на широко известном ассемблере с приставкой «турбо» от дяди Борланда. Собирал модули, конечно же, соответствующей 32-битной утилитой из того же пакета. Всё шло хорошо. Но в один прекрасный момент, когда я решил воспользоваться всей мощью технологии модульного программирования и разбил программу на два модуля, начал у меня вылезать весьма странный глюк.

Секция данных вместо того, чтобы записываться в PE-екзешник, где ей положено быть, наглухо затирала досовскую заглушку. Проблема была гадкая, появлялась по совершенно непонятным причинам: буквально лишний байт добавишь в данные — пропадает. Я уже старался не дышать на код. В конце концов сборщик вообще отказался кушать мои модули, мотивируя это так: «Fatal: General error in module <xxx>». А что за ошибка? Ни ответа, ни привета.

Очень скоро мне это надоело, и я перешёл на более современный и даже ещё живой сборщик от не менее известного производителя, продукты которого использовались для написания почти что всех программ незадолго до эпохи расцвета Win32. Он съедал объектные модули моей проги просто на ура. Но мысль о причине проблемы всё продолжала и продолжала меня беспокоить. Ведь это достаточно серьёзный баг, и если бы дело было именно в сборщике, наверное, кто-то давным-давно бы это заметил и написал в инете. Гуглю ошибку. И ничего — никто с подобным не сталкивался. А может, у меня версия сборщика какая-то корявая или битая? Да нет, перепробовал все возможные сборки пакета — везде версия одна и та же.

И тут в голову приходит последний вариант: может, что-то не так с моими объектными модулями? Но, простите, как же такое возможно? Ведь они скомпилированы при помощи проги из того же пакета. Неужели она может выдать объектный код, который по каким-то причинам не совместим со сборщиком от того же производителя?

Ну ладно. Опять юзаю тот же метод, что и в прошлый раз: иду от обратного. Вот рядом в папке Examples лежит прога, которая прекрасно компилируется. Скармливаю главный объектный модуль моей программы и .obj этой проги TDump’у и снова начинаю играть в игру «найди 10 отличий». Поначалу разницы никакой не видно, но потом…

Догадка поразила меня, как гром среди ясного неба. В сегменте данных не хватало некоторых переменных, которые там должны быть, и он зачем-то был разбит на несколько секций. И тут до меня дошло: это неинициализированные переменные! Те самые, для которых при определении вместо начального значения ставится значок вопросика.

Я никогда не придавал этой фишке никакого значения. Напишу ли я «hInstance dd 0» или «dd ?» — какая разница? В конечном результате сборщик всё равно всё проинициализирует и поставит ноль. Или нет? В большинстве случаев всё именно так и было. Но я столкнулся с мелким, неприятным и противным багом в широко известном и протестированном сотнями людей продукте. Сборщик банально выпадал в осадок, если секция данных начиналась с неинициализированной переменной! Вот так просто: просто поменяй местами переменные или проинициализируй — и всё, нет бага.

Вот мне и вам урок: старайтесь писать ваши программы так, чтобы они были совместимы хотя бы между собой — чего уж говорить о совместимости с другими…