Главная - Литература

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 [60] 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294

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

8.1. Защита программы от неправильных входных данных

Вы, возможно, слышали в школе выражение: «Мусор на входе - мусор на выходе». Это вариант предостережения потребителю от разработчиков ПО: пусть пользователь остерегается.

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

Существует три основных способа обработки входных мусорных данных, перечисленные далее.

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

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

«Garbage in, garbage out». Возможно, эту их школьную поговорку следует перевести нашей студенческой: «Каков стол, таков и стул». - Прим. перев.



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

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

Защита от проблем, кажущихся несущественными, может иметь большее значение, чем можно подумать (рис. 8-1). В оставшейся части этой главы я расскажу о проверке данных из внешних источников, проверке входных параметров и обработке неправильных входных данных.


Рис. 8-1. Часть плавучего моста Interstate-90 в Сиэтле затонула во время шторма, потому что резервуары были оставлены открытыми. Они наполнились водой, и мост стал слишком тяжел, чтобы держаться на плаву. Обеспечение заищты от мелочей во время проектирования может значить больше, чем кажется

8.2. Утверждения

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



ждение будет хранить молчание. Но как только записей станет больше 50 ООО, оно громко провозгласит об ошибке в программе.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 [60] 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294



0.0744