Windows

индекс
168,47

Почему бAARDак не убрали в релизе?

В бета-версиях Windows 3.1 был скрытый и зашифрованный код, который при запуске на DR-DOS выдавал непонятное сообщение о вымышленной ошибке.

В релизе решили подобными фокусами не заниматься, но код проверок и само сообщение не убрали: они так и остались внутри WIN.COM, и достаточно изменить один байт, чтобы AARD-код снова выполнялся при каждом запуске.

Зачем его оставили? Неужели Microsoft рассчитывала однажды в будущем разблокировать эти сомнительные проверки?
Конечно же, нет. Даже сообщение в релизе осталось неизменённое: «Please contact Windows 3.1 beta support.» Если бы сообщение действительно предназначалось для показа, после окончания бета-тестирования его бы обновили.

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

Ларри Остерман объясняет:
Обойти выполнение кода, вставив команду JMP, довольно безопасно; а если удалить его, в оставшемся коде изменятся смещения функций — т.е. это будет уже новый, непротестированный код. Бета-тестирование было уже окончено, поэтому разработчики старались не заменять протестированный код непротестированным.

Но с какой стати такое незначительное изменение кода может на что-то влиять? Крис Прэтли приводит пример:
Даже перелинковка кода, не то что перекомпиляция, может внести неожиданные баги. Несколько лет назад, когда мы работали над азиатским выпуском Word97 и уже считали весь код готовым, мы занялись его окончательной оптимизацией. У нас есть инструмент, который собирает статистику по выполнению отдельных функций, и переупорядочивает их в файле оптимальным образом; код функций при этом не изменяется. После оптимизации мы отдали код на окончательное тестирование, и — оба-на! — нашёлся баг. Когда тестировщики пользовались определённой функцией программы, на некоторых машинах оптимизированный код рушился. На тех же самых машинах та же самая функция отлично работала до оптимизации.

Мы занялись отладкой; но если мы добавляли в оптимизированную версию информацию для отладки, она больше не рушилась. Мы пробовали отлаживать её без дополнительной информации; но даже если мы просто запускали её под отладчиком, она больше не рушилась. Каким способом бы мы ни пытались узнать причину падений, программа не падала; но она падала абсолютно всегда, когда мы оставляли её в покое.

Мы уже собирались применить ICE (аппаратный отладчик), когда заметили закономерность: программа рушилась только на процессорах Pentium с частотой 150МГц и ниже, хотя не на всех. Это уже была зацепка. Мы пошли на сайт Intel, и заглянули в «список неточностей» (так они называют свои баги). Бинго! В процессорах Pentium была «неточность», в определённых условиях приводящая к сбою. В очень определённых условиях: если через 33 байта после JMP стоит условный переход, а сам JMP располагается на границе страницы памяти. Эта «неточность» была исправлена, начиная с выпуска Pentium 150МГц.

На самом деле, в чипах довольно часто бывают баги, хотя лишь немногие из них становятся общеизвестными. В конце концов, микрокод чипа пишут люди, а не боги. Обычно, как только производители чипа обнаруживают в нём баг, они сообщают производителям компиляторов; так что компиляторы генерируют код в обход обнаруженных багов, и обычные программисты с этими багами уже не сталвиваются. Оказалось, у нас был немного устаревший компилятор, который об этом конкретном баге ещё не знал.

Когда представитель Intel подтвердил, что таинственные падения программы могут быть вызваны этим самым багом, мы прошлись по оптимизированному коду, нашли виновную последовательность команд, и вручную переставили три байта так, чтобы расстояние между двумя прыжками составило 34 байта. Падения прекратились.

Теперь, когда кто-то меня уверяет, что его исправление «абсолютно безопасно», я всегда рассказываю эту историю. Ни одно изменение кода не может быть абсолютно безопасным.

Я и сам сталкивался с похожим багом: когда мы работали над Exchange 5.5, очередной билд рушился на одной тестовой машине — всегда на одной и той же. Мы несколько дней пытались выяснить причину, но безуспешно: баг исчезал от малейшего изменения кода. Зато он абсолютно всегда проявлялся, когда мы прекращали отладку. В конце концов мы, как и Крис, нашли «список неточностей»; и действительно, наш код страдал от одной из них. Не успокоившись исправлением конкретного билда, мы нашли набор опций компиляции, при которых баг был невозможен.

Поэтому неудивительно, что разработчики Windows оставили AARD-код в релизе: они уже много недель, если не месяцев, тестировали Windows с этим кодом, и знали наверняка, что когда этот код на месте, Windows работает. Работает ли Windows без него, они — перед самым релизом — не рискнули выяснять.



БAARDак был не единственной интересной особенностью бета-версии Windows 3.1.
Впервые Windows перехватывала нажатие Ctrl-Alt-Del, и показывала собственный экран «давайте я вам помогу закрыть зависшую программу». Пользовавшиеся Windows 3.x помнят, что этот экран был синим; в бета-версии же он был скучно чёрный.

Если пользователь подтверждал закрытие зависшего приложения, но Windows не удавалось его завершить (например, если зависших приложений в системе просто не было), то единственное, что Windows могла предложить, — перезагрузка.

В релизе Windows 3.1 эту странность исправили: теперь, если зависших приложений нет, Windows предлагает оставить всё как есть.



Другую похожую историю я читал, кажется, у Рэймонда Чена; мне не удалось сейчас найти первоисточник. Там Чен рассказывал, что в одном из древних билдов Windows обнаружили неиспользуемую переменную. Удалили её — в совершенно другом месте кода перестала работать функция. Вернули переменную — баг пропал.

В этот раз чипы были в порядке: проблема действительно оказалась у программистов. В сломавшейся функции была переменная, которая не во всех случаях инициализировалась перед использованием. Значением неинициализированной переменной был мусор, случайно оказавшийся в выделенной под неё ячейке стека; и так сложилось, что в этом месте всегда оказывался нуль. Нуль был подходящим значением для той переменной, и программа продолжала работать.

Когда удалили неиспользуемую переменную, все остальные переменные в программе «съехали» по стеку, и теперь в месте, отведённом под неинициализированную переменную, оказывалось какое-то другое значение. Теперь программа рушилась.

На удивление коллег Чена, бажная функция была написана за много месяцев до этого, и даже попала в предыдущий релиз Windows! Из-за удачного стечения обстоятельств, она всегда работала правильно, несмотря на баг, — именно поэтому баг так долго оставался незамеченным.

Чен приводил эту историю как объяснение того, почему в Windows XP есть фрагменты кода, которые никто не трогал со времён Windows 3.0. Никто не знает, сколько там есть невидимых багов; зато все знают наверняка: этот код работает.

+113
9 сентября 2010, 16:29
32

комментарии (61)

+5
crea7or #
А муравьед тут зачем? И это вроде как перевод, не?
+17
ophiuhus #
Это не муравьед, а багоед.
0
Goodkat #
И на фото он как раз нашёл какашку — код из Windows 3.0 в Windows 7.
+9
tyomitch #
Муравьед — это AARDvark.
Полтекста перевод, полтекста не перевод.
+1
crea7or #
Я не в претензии, статья очень хорошая и интересная. Но вот читаешь, а тут бах — муравьед. И сиди думай какого рожна он тут. А AARD это ещё дофига всего, в том числе aardwolf. Причём ничего из этого не имеет отношения к топику вообще. У вас ведь одна метафора уже есть бaardак, зачем ещё.
+2
tyomitch #
Это я ворую фирменный стиль соседней статьи, где читаешь, и вдруг бах — суши.
(Та статья, к слову, тоже не помечена как перевод.)

Первая заметка Остермана называлась «AARDvarks in your code», поэтому выбрал муравьеда. Но по большому счёту, это просто украшение.
–1
crea7or #
Зачем брать плохое? У вас ведь отличные топики!
+1
AYShestakov #
aardvark — зубкотруб, африканский муравьед, трубкозуб ©Lingvo
–7
aimodify #
Интересно, что именно не переписывалось со времен 3.0? Начсет утверждения, что «этот код работает» — не так уж он и работает.
+29
tyomitch #
Первое, что вспоминается из долгоживущего антиквариата — диалог установки шрифта.

+6
tyomitch #
Для желающих сосчитать отличия:

–1
freeAKK #
Кнопочки network и help
+4
mace #
[зануда]
Еще «Directories» -> «Folders», «Cancel» -> «Close», «Fonts» -> «fonts» и нижний лейбл около чекбокса.
[/зануда]
+1
sha1dy #
думал фейк! открыл и правда — иконки от win 3.1, иконки диалога нет — жесть.
0
frenzytechnix #
Этот диалог даже в Висте был такой, только в 7-ке наконец-то убрали.
+1
tyomitch #
Как раз в Висте его доработали: добавили предпросмотр шрифта.

–19
aimodify #
Непонятно за что минус, неужели сообщество придерживается мнения, что windows — это надежно? Тем более куски кода, которые не переписывались c 1990-года? Хоть пристрелите минусами не поверю!
+7
Christmas #
А по-вашему операционки с нуля каждый год переписываются?
+1
RazerSun #
20 лет, говорите не переписывалось?
Когда я пришел работать, наша сетка состояла из двух двухсотметровых кусков бывшего в употреблении многомодового оптоволоконного кабеля, которые под страхом смерти запрещалось трогать даже для перекроссировки. Мне, по наивности, казалось что их вот вот заменят, и все станет хорошо. Прошло уже пять лет. Как работали, так и работают. Параллельно им положили новые линии, но эти по прежнему никто не трогает. И они отлично работают — не припомню ни одного сбоя по их вине.
0
235 #
в юниксе есть код 30летней давности — работает до сих пор. Зачем переписывать атомарные операции и утилиты?
+6
dkr6 #
В данном случае видим яркое проявление принципа двух, взаимокомпенсирующих, ошибок…
При четном количестве ошибок в коде программа работает, ибо ошибки друг друга компенсирует…
Нельзя удалять по одной ошибке, только парами…

Я, конечно, понимаю, что программ без ошибок не бывает,
а 10 маркетологов смогут продать любой товар…
Но мне бы хотелось увидеть работу 10 квалифицированных программистов, а не маркетологов…

P.S.
В день тестера особо приятно читать такие статьи, спасибо.
0
dkr6 #
Вот, вспомнил, где оно валялось…
0
dkr6 #
0
Fragster #
хотлинкинг не работает
+1
dkr6 #
Просто не хватило потенции вставить разметку в комментарий :)

Иногда народ сильно нервничает, если другим надоело грызть кактус…
+3
bes_internal #
Да, точно помню, что если появился этот синий экран, то нужно было непромедлительно жать эскейп, и о чудо, машина не зависала, но нужно было успеть! Видимо где-то было переполнение, т.е баг в экране смерти. Такие дела (:
+7
DaemonI #
Эх, возможно на Хабре воспримут эти ситуации как нечто удивительное, но любой С/С++ программист огреб таких вот странных багов порядочно :) В условиях вседозволенности сорвать стек, запортить кучу или таблицу виртуальных функций — раз плюнуть, и проблема будет гораздо сложнее пресловутых

#define TRUE FALSE; // Дебажте п-сы
+1
HoochieMen #
Последняя строчка — эталон программерской издевки :D
+7
anarleen #
#define TRUE rand()>0.5 — это лучше.
+1
mambet #
Вспоминается комментарий в так называемых «исходиках windows», коии гуляли по сети. Что-то вроде "// Не убирайте этот комментарий!!! Это нарушит процесс сборки!!!"
+1
kekekeks #
Ну, у меня в коде одного проекта есть нечто подобное — там в процессе досборки разного хлама из некоторых исходников grep-ом выдёргиваются нужные для работы данные.
0
Halt #
Ну вот вы смеетесь. А попробуйте скомпилировать следующий код ;)

// This function does not working… :-\
void main(int argc, char** argv) {
int i = 42;
}
0
Halt #
*is not, прошу прощения :)
0
mambet #
Я неплохо знаю С, так что могу и так сказать, что будет. Там было другое.
Идея про grep'анье мне кажется более правдоподобной.
Ещё есть вариант — что компилятор падал, такое тоже случается на определённых комбинациях символов, сам видел.
0
Halt #
Да все понятно. И про грепанье и про компиляторы. В одном проекте, с которым приходилось работать там вообще, исходники и хедеры ездили между десятком директорий (страх и ужас). С помощью скриптов. Да и в тех же борладновских компиляторах полно ошибок.
+2
Beholder #
«Как страшно жить!»

Мы думаем, что сидим в чистеньких светленьких уютненьких офисах, а на самом деле под нами грязные мокрые подвалы с невесть каким мусором. В программах, оказывается, всё то же самое.
+6
RazerSun #
Когда б вы знали из какого сора, и какими «профессионалами» сделана последняя миля интернета… :)
0
Halt #
Езернету вообще памятник можно ставить :) Учитывая то, в каких условиях оно таки умудряется работать
–4
romx #
Неделя некрофилии на Хабрахабре.
+4
dkr6 #
Это память!!!
Только изучив досконально «как не нужно делать» можно научиться делать что-то хорошо…
Не изобретать же велосипед каждый раз…

А для многих это еще и ностальгия :)
+12
ophiuhus #
Сидит программист, отлаживает программу. Подходит сынишка:
— Папа, почему солнышко каждый день встает на востоке, а садится на западе?
— Ты это проверял?
— Проверял.
— Хорошо проверял?
— Хорошо.
— Работает?
— Работает.
— Каждый день работает?
— Да, каждый день.
— Ну, тогда, ради бога, сынок, ничего не трогай, ничего не меняй…
–2
Arris #
Да-да-да =)
0
gene4000 #
Такие вещи у многих встречаются. Но одно дело, когда программирование хобби и ты полдня читаешь кучу кода не понимая в чем проблема, прежде чем отключить оптимизацию в компиляторе и получив рабочую программу, и совсем другое, когда программа создается большими мощностями и продается за деньги.
+1
gavaec #
нет ничего более постоянного чем временное.

когда-то на 1й работе написал одну функцию на javascript и назвал её что-то типа test_function_чтототам, подумал получится — исправлю. потом перед очередным дедлайном потребовали выложить всё быстро, чтобы начальство посмотрело, а потом я уволился. ) через полгода зоходил на сайт, а функция всё та же там.
0
Arris #
А еще бывают куски кода, которые никогда не исполняются, но убрать их просто не доходят руки.

Типа:
a = 0;
if (a=0) {огромный кусок скрипта} else {еще один огромный кусок скрипта}

Первоначально предполагалось что в а окажется результат какого-то там вызова, но получилось, что он там никому не сдался :)
+2
AnatolyB #
Зато в Линуксе перекомпилировать ядро, программу или приложение — это в порядке вещей.

А Win32-программа, запущенная с помощью Wine получает статус работающей, если сразу не упала.

Что это, феномен необычайной надежности, или синдром непуганного дурака?
–3
al_one #
Н-да-а, как же всё там ненадёжно. А от слова «рефакторинг» у программистов из Майкрософта наверное инфаркт случается.
+5
smmurf #
Вы серьезно считаете, что в микрософте не делают рефакторинг, не знают что это такое, и пишут левой пяткой?
Попробуйте поддерживать проект такого масштба таким количеством человек столько лет. Посмотрим, что будет у вас в коде.
+2
al_one #
Любому человеку, не обделённому интеллектом, понятно, что это была гипербола. В МС огромный штат программистов и пишется много разного ПО, поэтому нельзя всех стричь под одну гребёнку.
Но вам не кажется, что метод «как-то работает и фиг с ним» грозит большими проблемами с кодом в будущем? Если даже перекомпиляция какого-то конкретного куска кода грозит всё сломать, то о каком рефакторинге именно этого куска кода может идти речь? Если при перелинковке что-то ломается, значит есть проблема: в коде, в компиляторе или даже в процессоре. Запрет на удаление старого кода это не решение проблемы, а закапывание головы в песок.
Аргумент «добейся сам», оставьте, пожалуйста, при себе.
+6
tyomitch #
Но вам не кажется, что метод «как-то работает и фиг с ним» грозит большими проблемами с кодом в будущем?

Этот код протестирован. Не по-опенсорсовски протестирован, «запустился и не упал», а все поддерживаемые функции протестированы во всех поддерживаемых конфигурациях.
Мало кто из софтверных компаний вообще может себе позволить настоящее тестирование.

Если даже перекомпиляция какого-то конкретного куска кода грозит всё сломать, то о каком рефакторинге именно этого куска кода может идти речь?

Чего ради рефакторить код, если он уже готов и работает?
Приводить его в соответствие с модными на этой неделе стандартами разработки?

Запрет на удаление старого кода это не решение проблемы, а закапывание головы в песок.

Проблемы нет, решать нечего: код работает.
If it ain't broke, don't fix it.
+2
al_one #
Оно тестируется на текущих конфигурациях. И невозможно предусмотреть абсолютно всё. Ну хорошо, сегодня один баг скомпенсировал другой, и тестирование прошло удачно, а завтра Интел выпускает новый процессор с каким-нибудь, например, супер хитрым кэшированием, и уже в неинициализрванной переменной будет мусор, а не ноль (пример из поста). А помните, у некоторого софта были проблемы, когда на дескопах стали появляться многоядерные процессоры? Потому что баг с неправильной синхронизацией не проявлял себя, пока 2 потока не стали выполняться реально одновременно. А ведь всё было протестировано.

Чего ради рефакторить код, если он уже готов и работает?
Приводить его в соответствие с модными на этой неделе стандартами разработки?

Предлагаете каждую новую версию начинать писать с нуля? И рефакторинг это не мода, это необходимость, хотя бы чтобы не превратить код в лапшу.

Проблемы нет, решать нечего: код работает.
If it ain't broke, don't fix it.

Вот это и есть принцип «как-то там работает себе, непонятно как, ну и ладно». А то, что при перекомпиляции что-то ломается, это наверно из-за плохой фазы Луны.
+1
tyomitch #
Оно тестируется на текущих конфигурациях. И невозможно предусмотреть абсолютно всё.

Верно! Именно поэтому история началась с того, что менеджеры MS решили сэкономить на тестируемых конфигурациях, и объявили DR-DOS неподдерживаемой платформой. Причём с формулировкой, «если на вашей DR-DOS не работает наша Windows, то пусть Novell разбирается.»

И я уверяю, если завтра Intel выпустит новый процессор, на котором из-за супер-хитрого кэширования не запустится Windows, то это не MS будет чинить свои баги, а Intel будет придумывать, как их обойти ;)
По той же самой логике: «у всех всё всегда работало, а тут на новом процессоре вдруг не работает, конечно же процессор виноват.»
–2
al_one #
И в результате везде костыли, неиспользуемые участки кода 20-летней давности и двойной штат программистов и тестеров. Разве к этому мы должны стремиться?)
+2
tyomitch #
А что вы предлагаете взамен?
«Просто писать код без багов»?
–2
al_one #
А вы можете писать код без багов? Я — нет, в Майкрософт тоже не боги работают. Поэтому я предлагаю исправлять баги, а не закрывать на них глаза.
+1
RomanNikitin #
по общению с ребятами в Микрософт (в этом году) могу сказать что там серьезно к этому подходят. И код-ревью на новый код и рефакторинг и очень серьезное отношение к любям маломальским багам системы.

Но без костылей и им приходится очень сложно… Микрософт уже давно вырос из размеров одной айти компании, там уже давно что-то типа кучи микро-компаний, использующих код друг друга, что часто может приводить и к костылям и багам и к переписыванию аналогичной функциональности под свои нужды кода другой команды.
0
al_one #
Молодцы, раз стараются. Наверно руководство поняло, что на одном пиаре по блогам (например на Хабре :) ) и обливании грязью опенсорсников далеко не уедешь.
0
RomanNikitin #
почему вы так предвзяты и думаете что в компании работодатель №1 в США работают полные дибилы?
0
al_one #
О-хо-хо. Где я говорил про дебилов? Как минимум талантливые бизнесмены там работают.
0
asci #
помню, долго бился головой о потолок, когда делфи 7 выдавала мне ошибку в комментарии. в итоге оказалось другой редактор добавил непечатный символ в код и компилятор с ума сходил=)
+5
wersoo #
оффтоп
Увидел у автора ник знакомый, tyomitch.
Вспомнилось как давненько учился я VB и запрашивал советов на форумах различных, мало кто что дельное советовал, а этот дядька помогал. И впоследствии я нашел на этом форуме ответы на многие вопросы. И зачастую это были тоже его ответы.
Спасибо тебе, tyomitch. У меня все

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.