Читаем 19 смертных грехов, угрожающих безопасности программ полностью

[e:\projects\19_sins\perl foo.pl

4294967295 = 4294967295 – 4294967295 + 1 = 4294967296

4294967295 = 0xffffffff – 4294967295 + 1 = 4294967296

Используется printf со спецификатором %d

$i = -1, $i + 1 = -1

Тестируется граничный случай деления

0x80000000/-1 = -2147483648

0x80000000/-1 = -2147483648

На первый взгляд, результат выглядит странно, особенно когда используется printf с форматной строкой (в отличие от обычной функции print). Первым делом в глаза бросается то, что мы можем присвоить переменной максимально возможное значение без знака, но после прибавления к нему 1 она либо увеличивается на единицу, либо – если печатать с помощью %d – вообще не изменяется. Загвоздка в том, что на самом деле вы оперируете числами с плавающей точкой, а спецификатор %d заставляет Perl преобразовать double в int. В действительности никакого переполнения нет, но при печати результатов создается впечатление, будто оно произошло.

В силу особенностей работы с числами в Perl мы рекомендуем быть очень осторожными при написании на этом языке приложений, в которых много математических операций. Если вы не разбираетесь досконально в арифметике с плавающей точкой, то можете столкнуться с весьма поучительными сюрпризами. Другие языки высокого уровня, например Visual Basic, тоже иногда производят преобразования в числа с плавающей точкой. Следующий код иллюстрирует, что в таком случае происходит:

...

print (5/4)."\n";

1.25

Для большинства обычных приложений Perl ведет себя предсказуемо и работает великолепно. Но не забывайте, что вы имеете дело не с целыми числами, а с числами с плавающей точкой, – а это «две большие разницы».

<p>Где искать ошибку</p>

Любое приложение, в котором производятся арифметические операции, подвержено этому греху, особенно когда некоторые входные данные поступают от пользователя и их правильность не проверяется. Особое внимание обращайте на вычисление индексов массивов и размеров выделяемых буферов в программах на C/C++.

<p>Выявление ошибки на этапе анализа кода</p>

При написании программ на языках C/C++ надо обращать самое пристальное внимание на возможность переполнения целого числа. Теперь, когда многие разработчики осознали важность проверок размеров при прямых манипуляциях с памятью, атаки направлены нате арифметические операции, с помощью которых эти проверки выполняются. Следующими на очереди стоят С# и Java. Прямые манипуляции с памятью в этих языках запрещены, но тем не менее можно допустить почти все ошибки, которые характерны для С и С++.

Ко всем языкам относится следующее замечание: проверяйте входные данные прежде, чем каким–либо образом их использовать! В Web–серверах Microsoft IIS 4.0 и 5.0 очень серьезная ошибка имела место из–за того, что программист сначала прибавил к переменной 1, а затем проверил, не оказался ли размер слишком большим. При тех типах, что он использовал, 64К–1 + 1 оказалось равно нулю! На соответствующее извещение есть ссылка в разделе «Другие ресурсы».

C/C++

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

...

THING* AllocThings(int a, int b, int c, int d)

{

int bufsize;

THING* ptr;

bufsize = IntegerOverflowsRUs(a, b, c, d);

ptr = (THING*)malloc(bufsize);

return ptr;

}

Ошибка скрывалась в функции, вычисляющей размер буфера, к тому же найти ее мешали загадочные, ничего не говорящие читателю имена переменных (и литералов, которые представлены типом signed int). Если у вас есть время на доскональный анализ, проследите порядок вызова всех ваших функций вплоть до обращений к низкоуровневым библиотечным функциям или системным вызовам. И напоследок выясните, откуда поступают данные. Можете ли вы утверждать, что аргументы функций не подвергались манипуляциям? Кто контролирует аргументы: вы или потенциальный противник?

По мнению автора языка Perl, величайшим достоинством программиста является лень! Так давайте пойдем простым путем – заставим потрудиться компилятор. Включите уровень диагностики /W4 (для Visual С++) или–Wall либо–Wsign–compare (для gcc) – и вы увидите, как много в вашей программе мест, где возможны проблемы с целыми числами. Обращайте внимание на все предупреждения, касающиеся целых чисел, особенно на те, в которых говорится о сравнении знаковых и беззнаковых величин, а также об усечении.

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных