Непсихологические тесты Крис Касперски ака мыщъх Спецвыпуск: Хакер, номер #053, стр. 053-060-5 Вывод диагностической информации Самое страшное - когда программа неожиданно делает из обрабатываемых чисел "винегрет". Совершенно непонятно, кто в этом виноват и откуда надо плясать. Ошибка в одной функции может аукаться в совершенно посторонних и никак не связанных с ней местах. Удар по памяти, искажение глобальных переменных или флагов (со)процессора. Здесь дамп уже не помогает. Застывшая картина статичного слепка памяти не объясняет, с чего началось искажение данных, в каком месте и в какое время оно произошло. Для локализации таких ошибок в программу заблаговременно внедряются "телеметрические" механизмы для генерации диагностической информации. В идеале следовало бы протоколировать все действия, выполняемые программой, запоминая все машинные команды в специальном буфере. Собственно говоря, SoftIce в режиме обратной трассировки (back trace) именно так и поступает, позволяя нам прокручивать программу задом наперед. Это чудовищно упрощает отладку, но… как же оно тормозит! Искусство диагностики как раз и состоит в том, чтобы отобрать минимум важнейших параметров, фиксирующих максимум происходящих событий. По крайней мере, отмечай последовательность выполняемых функций вместе с аргументами. Чаще всего для этой цели используется тривиальный fprintf для записи в файл или syslog для записи в системный журнал (в Windows NT это осуществляется вызовом API-функции ReportEven, экспортируемой библиотекой ADVAPI32.DLL). Начинающие допускают грубую ошибку, включая диагностику только в отладочную версию и удаляя ее из финальной: Никогда так не поступай! #ifdef _DEBUG_ fprintf(flog, "%s:%d a = %08Xh; b = %08Xh\n",__FILE__,__LINE__,a,b); #endif Когда такая программа упадет у пользователя, в руках программиста не окажется никакой диагностической информации, которая могла бы дать хоть какую-то зацепку. Лучше поступать так: Так поступать можно, но не нужно if (_DEBUG_) fprintf(flog, "%s:%d a = %08Xh; b = %08Xh\n",__FILE__,__LINE__,a,b); Если сбой повторяется регулярно, пользователь сможет взвести флажок DEBUG в настройках программы, и в следующий раз, когда она упадет, передаст программисту диагностический протокол, если, конечно, не переметнется к конкурентам. Штука. Правильный вариант выглядит так: Так поступать можно и нужно if (2*2 == 4) fprintf(flog, "%s:%d a = %08Xh; b = %08Xh\n",__FILE__,__LINE__,a,b); Грамотно отобранная телеметрическая информация отнимает совсем немного места и должна протоколироваться всегда (естественно, за размером log-файла необходимо тщательно следить, лучше всего если он будет организован по принципу кольцевого буфера). Некоторые программисты используют функцию OutputDebugString, посылающую информацию на отладчик. Если отладчик не установлен, можно воспользоваться утилитой Марка Руссиновича DebugView или аналогичной ей. Впрочем, пользы от такого решения все равно немного. Это тот же логинг, включаемый по требованию, а логинг должен быть включен всегда! |