Простая ошибка при кодировании — не значит нестрашная ошибка
Популяризируя статический анализатор кода PVS-Studio, мы обычно пишем статьи для программистов. Однако, на некоторые вещи программисты смотрят одностороннее. Именно поэтому и существуют менеджеры программных проектов, которые могут управлять процессом развития проекта направлять его в нужное русло. Я решил написать несколько статей, целевой аудиторией которых являются менеджеры программных проектов. Эти статьи помогут им лучше ориентироваться в вопросах использования методологии статического анализа кода. Сейчас мы рассмотрим ложный постулат: «ошибки кодирования несущественны».
Недавно я написал статью "Статья о статическом анализе кода для менеджеров, которую не стоит читать программистам". Вполне закономерно к ней начали оставлять комментарии о том, что нет пользы от инструмента поиска простых ошибок. Приведу один из таких комментариев:
Причина простая: основные баги — в алгоритмах. В работе аналитиков, математиков, постановщиков, алгоритмистов. А багов при кодировании — не так много.
В общем, ничего нового. Опять мы встречаемся с мифом, что профессиональные разработчики не допускают простых ошибок. А если и допускают, то это не страшно: такие ошибки легко найти и, как правило, они не критичные.
Обсуждать утверждение, что профессионалы не допускают ляпов, я смысла не вижу. Эта тема уже много раз была разобрана мною в статьях. В конце концов, если всё так просто, почему все эти профессионалы наделали так много ошибок в известных проектах. На данный момент, нами найдено уже более 11000 ошибок в открытых проектах, хотя мы никогда не стремились выявить как можно больше ошибок. Это просто побочный продукт написания статей.
Сейчас мне интереснее обсудить вот какую тему: многие программисты считают, что по-настоящему серьезные ошибки можно допустить только при реализации алгоритмов. Вот здесь я хочу предостеречь менеджеров — это не так. Любая ошибка может быть критичной. Я не отрицаю, что ошибки в алгоритмах крайне важны, однако, не следует недооценивать важность опечаток и обыкновенных ляпов.
Некоторые программисты заявляют: раз анализатор не умеет искать ошибки в сложных алгоритмах, то он не нужен. Да, сложные алгоритмические ошибки анализатор искать не умеет, для этого нужен искусственный интеллект, который пока не создан. Тем не менее, искать обыкновенные ошибки в коде столь же важно и нужно, как и алгоритмические ошибки.
Чтобы не быть голословным, предлагаю вам 3 примера.
Для начала можно вспомнить критическую уязвимость в iOS, появившуюся из-за двойного goto.
if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
Подробности изложены в статье Apple’s SSL/TLS bug. Не важно появилась эта ошибка из-за опечатки или неудачного merge. Явно, это «механическая» ошибка, не имеющая отношения к математике или алгоритмам. При этом, подобная ошибка обнаруживается анализатором PVS-Studio.
Теперь вспомним уязвимость в MySQL: Security vulnerability in MySQL/MariaDB sql/password.c.
char foo(...) {
return memcmp(...);
}
Ошибка возникает из-за неявного приведения типа (int -> char), при котором отбрасываются значения старших битов. Это вновь ошибка, которая не имеет отношения к сложным алгоритмам и прекрасно выявляется анализатором PVS-Studio. Не смотря на свою простоту, ошибка приводит к тому, что на некоторых платформах в 1 случае из 256 процедура сравнения хэша с ожидаемым значением всегда возвращает значение ‘true’, независимо от хэша.
Третий пример. Я участвовал в разработке пакета численного моделирования газодинамических процессов. Масса математики, алгоритмов и т.д. И, конечно, были связанные с этой математикой ошибки и проблемы. Однако, мне намного больше запомнились проблемы, возникающие из-за переноса кода на 64-битные системы. Кстати, именно тогда и зародилась идея создать анализатор Viva64, который потом развился в PVS-Studio (история: как 10 лет назад начинался проект PVS-Studio).
Одна из ошибок была связана с неправильным позиционированием в файле с помощью функции _fseeki64. Пакет моделирования, став 64-битным, смог обрабатывать больший объем данных и, как результат, записывать данные большего объема на диск. Вот только потом, не мог их правильно прочитать. Причем, нельзя сказать, что код был написан как-то уж очень плохо. Приблизительно там было так:
unsigned long W, H, D, DensityPos;
....
unsigned long offset = W * H * D * DensityPos;
res = _fseeki64(f, offset * sizeof(float), SEEK_SET);
Возникает переполнение при перемножении переменных. В защиту программиста можно сказать, что, когда он писал этот код, сложно предположить, что в Win64 (ILP32LL) размер типа long останется 32-битным. Эту ошибку искали очень долго. Когда приводится вот такой псевдокод, кажется всё простым и понятным. На практике же, очень сложно было понять, почему при превышении определенного порога объёма обрабатываемых данных, начинаются странные ошибки. Неделю отладки легко можно было бы заменить проверкой кода с помощью PVS-Studio, который в два счёта нашел бы описанный баг. Алгоритмы и математика при переходе на 64-битную систему как раз не повлекли за собой никаких сложностей.
Как видите, простые ошибки могут приводить к серьезным последствиям. Лучше находить их как можно больше с помощью статического анализатора, а не проводя часы и дни в отладчиках. И уж тем более, лучше найти ошибку самим. Худший вариант: выясняется, что ваше приложение содержит уязвимость, но оно уже инсталлировано на десятках тысяч компьютеров.
Да и просто полезно найти как можно больше простых ошибок с помощью инструментов, чтобы посвятить себя поиску дефектов в алгоритмах и созданию новой функциональности.
Кстати, предлагаю менеджерам, читающим эту статью, воспользоваться нашими услугами по проверке их проектов. Предлагаем заключить маленький контракт, в рамках которого мы исследуем проект и исправим все ошибки, которые сможем найти. Во-первых, это в любом случае будет полезно, а во-вторых, если результат вам понравится, это откроет путь для дальнейшего сотрудничества. В случае необходимости мы готовы подписать NDA. Предлагаю обсудить детали по почте.
Дополнительные ссылки:
- Страница PVS-Studio.
- Мифы о статическом анализе. Миф первый – статический анализатор это продукт разового применения.
- Мифы о статическом анализе. Миф второй – профессиональные разработчики не допускают глупых ошибок.
- Мифы о статическом анализе. Миф третий – динамический анализ лучше чем статический.
- Мифы о статическом анализе. Миф четвёртый – программисты хотят добавлять свои правила в статический анализатор.
- Мифы о статическом анализе. Миф пятый – можно составить маленькую программу, чтобы оценить инструмент.
- В дополнении к пятому мифу: Почему я не люблю синтетические тесты.
Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Andrey Karpov. If the coding bug is banal, it doesn’t meant it’s not crucial
Автор: