Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
A_Kpo.pdf
Скачиваний:
157
Добавлен:
10.06.2015
Размер:
1.82 Mб
Скачать

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

Например, проигнорировав ошибку чтения из файла блока данных, программа получит в своё распоряжение не те данные, которые она должна была считать, а какие-то другие. Результаты их использования предугадать невозможно.

Исключения обнаруживаются средствами языков программирования, аппаратуры ЦВМ или операционной системы и позволяют передать в исполняемый код наличие возникшие ошибки или исключительные ситуации. Если отмеченные средства встречают ошибочную ситуацию, то они не знают, как её обработать и генерируют «исключение», т. е. фактически «умывают руки» со словами: «Я не знаю, что с этим делать, надеюсь, кто-нибудь другой знает, как на это реагировать!» Действительно операционная система, например, не имеющая понятия о смысле и контексте приложения, в котором обнаружена исключительная ситуация, может вернуть управление такой части прикладной программы, которая, лучше знает, как интерпретировать ошибку и сделать с ней что-то осмысленное и правильное в данном конкретном случае.

Действительно, во многих языках программирования возникновение исключительных ситуаций приводит к аварийному останову. Для СТС часто это не очень удачный выход. Поэтому во многих языках, например, в языке Ада программисту дается возможность написать подпрограмму обработки исключительной ситуации, которая автоматически вызывается при возникновении этой ситуации и позволяет провести соответствующие восстановительные операции. В дальнейшем эта подпрограмма может передать управление в точку, где возникла ситуация или в любую другую точку, либо «мягко» завершить выполнение программы.

48. Выбор способа обработки некорректных входных данных

Существует три основных шага при обработки входных данных с «защитой от мусора».

1.Необходимо проверять все данные из внешних источников Получив данные из файла, от пользователя, из сети или любого другого внешнего интерфейса, удостоверьтесь, что все значения попадают в допустимый интервал. Проверьте, что числовые данные имеют разрешенные значения, а строки достаточно коротки, чтобы их можно было обработать. Если строка должна содержать определенный набор значений (скажем, идентификатор финансовой транзакции или что-либо подобное), проконтролируйте, что это значение допустимо в данном случае, если же нет — отклоните его. Если вы работаете над приложением, требующим соблюдения безопасности, будьте особенно осмотрительны с данными, которые могут атаковать вашу систему: попыткам переполнения буфера, внедренным SQL-командам, внедренному HTMLили XML-коду, переполнениям целых чисел, данным, передаваемым системным вызовам и т. п.

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

[Введите текст]

3.Необходимо решить, как обрабатывать неправильные входные данные. Что делать, если в обнаружен неверный параметр? В зависимости от ситуации вы можете выбрать один из нескольких подходов, описанных ниже.

49. Способы обработки возможных ошибок

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

Вернуть нейтральное значение. Иногда наилучшей реакцией на обнаруженные неправильные данные будет продолжение выполнения и выдача в качестве результата заведомо безопасного значения. Численные расчеты могут возвращать 0. Операция со строкой может вернуть пустую строку, а операция с указателем — пустой указатель. Метод рисования в видеоигре, получивший неправильное исходное значение цвета, может по умолчанию использовать цвет фона или изображения. Однако в методе рисования рентгеновского снимка ракового больного вряд ли стоит применять «нейтральное значение». В таких случаях лучше прекратить выполнение программы, чем показать пациенту неправильные результаты.

Заменить следующим корректным блоком данных. Условия обработки потока данных иногда таковы, что следует просто вернуть следующие допустимые данные. Если при чтении информации из базы данных встречена испорченная запись, можно просто продолжить считывание, пока не будут найдены корректные данные. Если вы считываете показания термометра 100 раз в секунду и один раз не получили достоверного измерения, можно просто подождать 1/100 секунды и обратиться к следующему показанию.

Вернуть тот же результат, что и в предыдущий раз. Если программа считывания показаний термометра, один раз не получила измерение, она может просто вернуть то же значение, что и в предыдущий раз. В зависимости от приложения температура скорее всего не сильно изменится за 1/100 секунды. Если в видеоигре запросу на прорисовку части экрана передано неверное значение цвета, вы можете просто вернуть тот же цвет, что и раньше. Но, авторизуя транзакции в

банкомате, вы, пожалуй, не захотите использовать «то же значение, что и в предыдущий раз» — ведь это будет номер счета предыдущего клиента!

Подставить ближайшее допустимое значение В некоторых случаях вы можете вернуть ближайшее допустимое значение. Часто это обоснованный подход для получения показаний откалиброванных инструментов. Так, термометр мог бы быть откалиброван от 0 до 100 градусов по Цельсию. Если вы получаете значение меньше 0, можно заменить его на 0, как ближайшее допустимое значение. Если же значение больше 100, можно подставить 100. Если в операции со строкой ее длина заявлена меньшей 0, можно принять ее за 0.

Записать предупреждение в файл журнала и продолжить работу. Этот подход можно сочетать с другими способами, такими как подстановка ближайшего допустимого значения.

72

Прекратить выполнение. Некоторые системы прекращают работу при возникновении любой ошибки. Этот подход оправдан в приложениях, критичных к безопасности. Например, какая реакция на ошибку будет наилучшей, если ПО, контролирующее радиационное оборудование для лечения рака, получит некорректное значение радиационной дозы? Надо ли использовать то же значение, что и в предыдущий раз? А может, ближайшее допустимое или нейтральное значение?

В этом случае остановка работы — наилучший вариант. Мы охотнее предпочтем перезагрузить машину, чем рискнуть применить неправильную дозу. Похожий подход применим и для повышения безопасности Microsoft Windows. По умолчанию Windows продолжает работать, даже если журнал безопасности переполнен. Но вы можете изменить конфигурацию Windows так, что при заполнении журнала сервер будет прекращать работу. Это может быть полезно для систем повышенной секретности.

Что важней устойчивость или корректность?

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

В приложениях, связанных с управлением подвижными объектами, технологическими процессами устойчивость, напротив, предпочтительнее корректности. Какой-то результат всегда лучше, чем прекра-

щение работы.

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

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

Некоторые языки позволяют игнорировать возвращаемое функцией значение (в C++ вы не обязаны что-то то делать с возвращенным результатом), но не игнорируйте информацию об ошибке! Проверяйте значение, возвращаемое из функции. Даже если вы считаете, что ошибка в функции возникнуть не может, все равно проверяйте. Весь смысл устойчивого к ошибкам (защитного) программирования в защите от оши-

бок, которых вы не ожидаете.

[Введите текст]

50. Утверждения и общие принципы их использования

Утверждения проверяют условия событий, которые никогда не должны происходить. Обработчик оши-

бок обычно проверяет некорректные входные данные, утверждения — ошибки в программе.

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

Пример утверждения (Java)

assert denominator /= О : "denominator is unexpectedly equal to 0.";

В этом утверждении объявляется, что denominator не должен быть равен 0. Первый аргумент — denominator /= 0 — логическое выражение, принимающее значение true или false. Второй — это сообщение, выводимое, когда первый аргумент равен false (т. е. утверждение ложно).

Например, утверждения можно применять при проверке таких условий:

значение входного (выходного) параметра попадает в ожидаемый интервал;

файл или поток открыт (закрыт), когда метод начинает (заканчивает) выполняться;

указатель файла или потока находится в начале (конце), когда метод начинает (заканчивает) выполняться;

файл или поток открыт только для чтения, только для записи или для чтения и записи;

значение входной переменной не изменяется в методе;

указатель ненулевой;

массив или другой контейнер, передаваемый в метод, может вместить по крайней мере X элементов;

таблица инициализирована для помещения реальных значений;

контейнер пуст (заполнен), когда метод начинает (заканчивает) выполняться;

результаты работы сложного, хорошо оптимизированного метода совпадают с результатами метода более медленного, но написанного яснее.

Разумеется, это только основы, и конкретные методы могут содержать много специфических допущений, которые можно документировать, используя утверждения.

Необходимо использовать утверждения для документирования и проверки предусловий и постусловий. Предусловия — это соглашения, которые клиентский код, вызывающий метод или класс, обещает выполнить до вызова метода или создания экземпляра объекта. Предусловия — это обязательства клиентского кода перед кодом, который он вызывает.

Постусловия — это соглашения, которые метод или класс обещает выполнить при завершении своей работы. Постусловия — это обязательства метода или класса перед кодом, который их использует.

74

Утверждения — удобный инструмент для документирования пред- и постусловий. С этой целью можно использовать и комментарии, но в отличие от них утверждения могут активно т.е. динамически проверять, выполняются ли пред- и постусловия.

Существует мнение, что утверждения не предназначены для использования в промышленной версии — они в основном применяются при разработке и поддержке. В период разработки утверждения выявляют противоречивые допущения, непредвиденные условия, некорректные значения, переданные методам, и т. п. При компиляции штатной версии они могут быть удалены и, таким образом, не повлияют на производительность системы, так как объем кода утверждений может быть большим.

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

.Более правильный подход – штатная программа не должна отличаться от отладочного варианта и этот добавочный код должен остаться в промышленной версии.

Таким образом, необходимо использовать процедуры обработки ошибок для ожидаемых событий и утверждения для событий, которые происходить не должны. Если для обработки аномальной ситуации служит обработчик ошибок, он позволит программе адекватно отреагировать на ошибку. Если же в случае аномальной ситуации сработало утверждение, для исправления просто отреагировать на ошибку мало — необходимо изменить исходный код программы, перекомпилировать и выпустить новую версию ПО.

Изоляция повреждений программы, вызванных ошибками. Связь между «баррикадами» и утверждениями

Изоляция повреждений, или «баррикада», — это стратегия, сходная с тем, как изолируются отсеки в трюме корабля. Если корабль налетает на айсберг и в днище появляется пробоина, отсеки задраиваются, и остальная часть корабля не страдает. Баррикады также аналогичны брандмауэрам, предотвращающим распространение огня из одной части здания в другую. (Ранее баррикады и назывались брандмауэрами, но сейчас термин «брандмауэр» обычно относится к блокировке нежелательного сетевого трафика.)

Один из способов изоляции в целях устойчивого (защитного) программирования состоит в разработке набора интерфейсов в качестве оболочки для «безопасных» частей кода. Проверяйте корректность данных, пересекающих границу безопасной области, и реагируйте соответственно, если данные неправильные. Выделение части кода для работы с непроверенными данными, и части - для работы с только корректными данными, может быть эффективным способом освободить большую часть программы от ответственности за проверку допустимости данных

Тот же подход применим и на уровне класса. Открытые методы класса предполагают, что данные небезопасны и отвечают за их проверку и исправление. Если данные были проверены открытыми методами класса, закрытые методы могут считать, что данные безопасны.

[Введите текст]

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]