Разыменование нулевого указателя (CWE-476) представляет собой дефект, когда программа обращается по некорректному указателю к какому-то участку памяти. Такое обращение ведет к неопределенному поведению программы, что приводит в большинстве случаев к аварийному завершению программы.
Ниже приведен пример обращения по нулевому указателю. В данном случае, скорее всего, программа отработает без выдачи сообщений об ошибках.
#include <iostream>
class A {
public:
void bar() {
std::cout << "Test!\n";
}
};
int main() {
A* a = 0;
a->bar();
return 0;
}
А теперь рассмотрим пример, в котором программа аварийно завершит свою работу. Пример очень похож на предыдущий, но с небольшим отличием.
#include <iostream>
class A {
int x;
public:
void bar() {
std::cout << x << "Test!\n";
}
};
int main() {
A* a = 0;
a->bar();
return 0;
}
Почему же в одном случае программа отработает нормально, а в другом нет? Дело в том, что во втором случае вызываемый метод обращается к одному из полей нулевого объекта, что приведет к считыванию информации из непредсказуемой области адресного пространства. В первом же случае в методе нет обращения к полям объекта, поэтому программа скорее всего завершится корректно.
Рассмотрим следующий фрагмент кода на C++:
if( !pColl )
pColl->SetNextTxtFmtColl( *pDoc->GetTxtCollFromPool( nNxt ));
Нетрудно заметить, что если pColl == NULL, выполнится тело этого условного оператора. Однако в теле оператора происходит разыменование указателя pColl, что вероятно приведет к краху программы.
Обычно такие дефекты возникают из-за невнимательности разработчика. Чаще всего блоки такого типа применяются в коде для обработки ошибок. Для выявления таких дефектов можно применить различные методы статического анализа, например, сигнатурный анализа или symbolic execution. В первом случае пишется сигнатура, которая ищет в абстрактном синтаксическом дереве (AST) узел типа «условный оператор», в условии которого есть выражение вида! а, a==0 и пр., а в теле оператора есть обращение к этому объекту или разыменование этого указателя. После этого необходимо отфильтровать ложные срабатывания, например, перед разыменованием этой переменной может присвоиться значение:
if(!a) {
a = new A();
a->bar();
}
Выражение в условии может быть нетривиальным.
Во втором случае во время работы анализатор «следит», какие значения могут иметь переменные. После обработки условия if (!a) анализатор понимает, что в теле условного оператора переменная a равна нулю. Соответственно, ее разыменование можно считать ошибкой.
Приведенный фрагмент кода взят из популярного свободного пакета офисных приложений Apache OpenOffice версии 4.1.2. Дефект в коде был обнаружен при помощи статического анализатора программного кода AppChecker. Разработчики были уведомлены об этом дефекте, и выпустили патч, в котором этот дефект был исправлен ).
Рассмотрим аналогичный дефект, обнаруженный в Oracle MySQL Server 5.7.10:
bool sp_check_name(LEX_STRING *ident)
{
if (!ident || !ident->str || !ident->str[0] ||
ident->str[ident->length-1] == ' ')
{
my_error(ER_SP_WRONG_NAME, MYF(0), ident->str);
return true;
}
..
}
В этом примере если ident равен 0, то условие будет истинным и выполнится строка:
my_error(ER_SP_WRONG_NAME, MYF(0), ident->str);
что приведет к разыменованию нулевого указателя. По всей видимости разработчик в процессе написания этого фрагмента кода, в котором ловятся ошибки, просто не учел, что такая ситуация может возникнуть. Правильным решением было бы сделать отдельный обработчик ошибок в случае, когда ident=0.
Нетрудно догадаться, что разыменование нулевого указателя – это дефект, не зависящий от языка программирования. Предыдущие два примера демонстрировали код на языке C++, однако с помощью статического анализатора AppChecker можно находить подобные проблемы в проектах на языках Java и PHP. Приведем соответствующие примеры.
Рассмотрим фрагмент кода системы управления и централизации информации о строительстве BIM Server версии bimserver 1.4.0-FINAL-2015-11-04, написанной на языке Java:
if (requestUri.equals("") || requestUri.equals("/") || requestUri == null) {
requestUri = "/index.html";
}
В данном примере сначала идет обращение к переменной requestUri и только после этого происходит проверка на нулевой указатель. Для того чтобы избежать этого дефекта, достаточно было просто поменять очередность выполнения этих действий.
Теперь рассмотрим фрагмент кода популярной коллекции веб-приложений phabricator, написанной на php:
if (!$device) {
throw new Exception(
pht(
'Invalid device name ("%s"). There is no device with this name.',
$device->getName()));
}
В данном случае условие выполняется только если $device = NULL, однако затем происходит обращение к $device->getName(), что приведет к fatal error.
Подобные дефекты могут оставаться незамеченными очень долго, но в какой-то момент условие выполнится, что приведет к краху программы. Несмотря на простоту и кажущуюся банальность такого рода дефектов, они встречаются достаточно часто, как в open-source, так и в коммерческих проектах.
Update:
Ссылка на бесплатную версию AppChecker: https://file.cnpo.ru/index.php/s/o1cLkNrUX4plHMV
Комментарии (91)
mayorovp
10.01.2017 13:49+5Поддерживаемые спецификации языков программирования
ANSI С/С90/С99/С11;
C++98/C++2003/С++11/С++14;
Java 6/7 Language Specification;
PHP 4/5;
С# 5.0.В общем, кроме Си/C++ никакие языки толком не поддерживаются.
kishchenko
10.01.2017 14:05+6С# 5.0
Абсолютно не актуально, ибо на дворе уже 2017 с C# 7.0mayorovp
10.01.2017 14:14+3Также как Java 8 и PHP 7 (если уже новых версий не выпустили, я там не слежу особо). Собственно, потому я и выделил эти версии.
quzor
10.01.2017 14:37-8Можно подумать PVS-Studio с первых дней поддерживал C# и все новомодные фишки языков. Пройдет чуть больше времени, разработчики подтянут свой проект, вот тогда и посмотрим.
mayorovp
10.01.2017 14:44+4Но они и такой поддержки не заявляли. А тут поддержка как бы есть — но на самом деле ее нет.
Кстати, а при чем тут вообще PVS-Studio?
quzor
10.01.2017 14:51-2Потому, что наш уважаемый kishchenko — сотрудник Сипровер.
Который, конечно же не оставил без внимания этот нюанс.n0mo
10.01.2017 15:07+3Процитировав Ваш комментарий, я хотел сказать, что Вы же вроде за конкуренцию на Хабре…
Andrey2008
10.01.2017 14:24+5Кстати, интересный пример двойственности мира. Описывая подобные ошибки в наших статьях, мы обычно используем для кода вида:
if( !pColl ) pColl->SetNextTxtFmtColl( *pDoc->GetTxtCollFromPool( nNxt ));
Термин опечатка. Ведь в показанных примерах явно «дрогнула рука». Впрочем, это не значит, что это не серьезная ошибка. И обнаруживаем мы таких ошибок действительно много (примеры найденных ошибок в открытых проектах: V522, V595, V713). А двойственность в том, что эту ошибку можно назвать и уязвимостью. Думается мне, рано или поздно мы выпустим PVS-Studio для поиска уязвимостей, вообще ничего в нём не меняя, кроме названия диагностик и документации. :)
quzor
10.01.2017 14:26+2Долой PVS-Studio! Да здравствует конкуренция на Хабре.
mayorovp
10.01.2017 14:27+6Чему вы так радуетесь? Вы их прайс-то видели?
npoechelon
10.01.2017 15:16+1Прайс? Сейчас можно скачать лайт-версию (без ограничений по времени использования) бесплатно: https://file.cnpo.ru/index.php/s/o1cLkNrUX4plHMV
staticlab
10.01.2017 15:17+1И чем лайт отличается от фулл?
npoechelon
11.01.2017 13:21+1Лайт-версия — это полнофункциональный AppChecker с зафиксированной базой правил поиска дефектов на август 2016 года
npoechelon
10.01.2017 15:22-1Кстати, если кто-нибудь из уважаемых критиков испытает продукт в деле и сделает обзор, подарим наш фирменный настенный календарь)
pavel_pimenov
11.01.2017 08:48+2Для windows опишите подробнее по шагам как проверить .sln
который корректно собирается в Visual C++facet
11.01.2017 20:36+1У нас есть инструкция по конфигурированию проектов C/C++. Её можно скачать прямо из AppChecker — при создании проекта перейдите по ссылке «Перейти на страницу загрузки утилит и инструкции по конфигурированию» -> «Настройка парсера C/C++», там же можно скачать и утилиту для конфигурирования.
Шаги такие:
- запустить утилиту CppConfMonitor.exe
- пересобрать проект в Visual Studio
- остановить утилиту, введя «s» в ее консоли
- утилита сформирует архив, который нужно загрузить в AppChecker
mayorovp
10.01.2017 15:40+1Объясняю при чем тут прайс. После выхода версии PVS-Studio под Linux а также появления бесплатной лиценции со своеобразными, но все же выполнимыми, условиями, у нас осталась всего одна причина ненавидеть PVS-Studio — их секретный прайс.
И когда человек пришел сюда и написал в комментариях: "Долой PVS-Studio! Да здравствует конкуренция на Хабре." — мне и стало интересно, видел ли он ваш прайс. Я вот, к слову, его не нашел.
quzor
10.01.2017 15:44-3То то мы и наблюдаем как их бесплатной версией активно пользуются на гитхабе
Если серьезно, то это больше плевок в лицо, нежели нормальная бесплатная версия.kishchenko
10.01.2017 17:35+7Если правильно пользоваться поиском на гитхабе, то процент активного использования PVS-Studio Free резко возрастает.
kishchenko
10.01.2017 17:49+2Некоторые настройки поиска при переходе по ссылке не сохраняются, поэтому руками нужно переключить фильтр с «Best Match» на «Recently indexed», либо выбрать язык (C#/C++) из списка.
Результат: 2 351 упоминание в коде.mayorovp
11.01.2017 09:38+2UPD: там не "настройки не сохраняются", а нельзя выполнить поиск по всем открытым репозиториям по прямой ссылке. Надо обязательно либо вводить запрос вручную, либо после перехода по ссылке поменять любую настройку. И еще надо быть залогиненым — анонимам искать по всем репозиториям нельзя.
4144
11.01.2017 13:03+1У вас есть лайт версия под linux?
npoechelon
11.01.2017 13:05-2Лайт-версия AppChecker только под Windows, коммерческую можем собрать и под Linux, если такая потребность будет у наших заказчиков
staticlab
10.01.2017 15:06+7А почему AppChecker предлагает загружать архив с исходниками? А как же интеграция с системой контроля версий, CI? На дворе 2017 год!
Ещё и написали о "патенте", коим оказалось всего лишь свидетельство о регистрации ПО.
npoechelon
10.01.2017 15:59+1Интеграция с СУВ (git, subversion, mercurial) уже есть. Поддержка CI (Jenkins, TeamCity) также есть, но в альфа-версии, релиз планируем в феврале. Так же имеется консольный клиент, с помощью него можно в автоматическом режиме производить анализ и встраивать его в свою систему сборки.
Ряд алгоритмов, используемых в AppChecker, покрывается следующим патентом:
https://npo-echelon.ru/upload/iblock/7d0/7d01385cccfddcb4eb4c925db3fc3b7a.pngVolCh
11.01.2017 13:02Для оборонки вроде были характерны нейтральные названия вроде средмаша или вообще маскировка типа тракторного завода или вагоностроительного.
mtp
10.01.2017 21:44+1ЗАО «НПО „Эшелон“» Ничего себе! Название — прямо привет из оборонки 70-х. Ну, разве что «ЗАО» несколько выбивается из ассоциативного ряда.
Рад за отечественную разработку, честно.monah_tuk
11.01.2017 11:25В современных реалиях ЗАО только дополняет старый термин ;-)
ЗЫ только, вроде, с 2014 года классификация поменялась ЗАО -> АО, ОАО — ПАО.
asasasdd
11.01.2017 12:55+7Результат разработки AppChecker довольно предсказуем.
Компания Эшелон специализируется на проведении работ в системах сертификации ФСТЭК, МО, ФСБ. Для проведения этих работ много лет назад разработано средство анализа АК-ВС, осуществляющее ряд исследований по руководящему документу ФСТЭК по контролю наличия недекларированных возможностей. Те, кто с этим средством имел несчастье соприкасаться, знаком с его качеством реализации и функционирования.
В прошлом году был утверждён ГОСТ, разработанный компанией Эшелон, определяющий процесс безопасной разработки ПО. ГОСТ будет обязателен для применения компаниями, которые работают на рынке сертифицируемых решений. Это светлое будущее различных систем сертификации, в котором декларируется необходимость поиска программных дефектов (уязвимостей). Вот для этого и разрабатывается AppChecker. Ни разработчикам, ни потребителям, ни исследователям, ни экспертам не интересно качество реализации и функционирования средства анализа, всем нужна заветная бумажка — сертификат. Есть бумажка — ПО надёжно и безопасно.npoechelon
11.01.2017 12:57-4Александр, хорошая попытка вскрыть международный заговор строителей систем защиты информации!))
По поводу качества первой версии нашего продукта АК-ВС: качество – характеристика относительная и, если решили о ней поговорить, то давайте сравнивать с другими аналогичными решениями, а потом уже выплескивать эмоции. Продукт, как вам известно, не единственный на рынке, также никто не мешает вам разработать собственный инструмент анализа.
Правда, проводить тестирование лучше уже АК-ВС 2, который уже пару лет как представлен на рынке. Если у вас появятся конкретные предложения по улучшению нашего продукта, будем очень признательны.
Спасибо, что вспомнили ГОСТ Р 56939-2016. В его разработке приняло участие 105 компаний и было учтено более 300 замечаний (в том числе и от вашей). Нам о планах сделать его обязательным ничего неизвестно, но мы бы порадовались, так как вложили в ГОСТ массу интеллектуальных усилий: обратите внимание, что он не является переводом западного, а разработан специально под наши реалии. Если его читать внимательно, то можно заметить, что помимо статического анализа кода, реализованного в AppChecker, предусматривается и динамический анализ, и fuzzy-тестирование, и тестирование на проникновение и многие другие меры.
Александр, предлагаем вам, как эксперту скачать AppChecker и попробовать его в деле, и поделиться впечатлением на страницах Хабра, а мы вам подарим наш легендарный перекидной календарь!pavel_pimenov
11.01.2017 14:09+6Подпишите инсталлятор и исполняемые модули AppChecker сертификатом
не солидно выглядит такое распространение софта от фирмы с профилем по ИБ.
Не эксперт, но заинтригован… что в вашем календаре легендарного — он очень старый… за какой год?
asasasdd
11.01.2017 22:55+2npoechelon, нет никакого заговора, но есть безразличие и безответственность.
Вас оправдывает то, что аналогичные решения написаны такими же безразличными к результату разработчиками? Да и какие это решения, Аист-С? Все, кто работает в отрасли сертификации, прекрасно знает как работает АК-ВС и что большая удача найти хоть какие-то исходники, на которых он отработает без единого сбоя.
АК-ВС за последние годы стал стандартом де-факто в отрасли сертификации, новые лаборатории покупают у вас продукт, отправляют в ваш учебный центр своих сотрудников, которые после прохождения обучения начинают считают, что раз средство разрешено к применению ФСТЭКом, то это автоматически решает все проблемы. Старый добрый принцип — есть бумажка, значит всё защищено и надёжно. В итоге у среднего специалиста в отрасли сертификации долгие годы было убеждение, что надо просто запустить АК-ВС, скормить ему исходники, сгенерировать протоколы и отправить их для проведения экспертизы, где в их содержимое редко кто будет вчитываться на предмет корректности проведённых работы. Вот и вся работа, вся сертификация на НДВ.
АК-ВС 2 пару лет представлен на рынке, но при этом работает также некорректно (но чуть лучше, чем АК-ВС). При этом, по старой доброй традиции, это никому не мешает: ни вам — его продавать, ни регуляторам — его разрешать к применению, ни лабораториям — его непосредственно применять.
Первая редакция ГОСТ представляла собой РД НДВ в новой обёртке. Утверждённая редакция является просто учётом тех замечаний, о которых вы упомянули. Если я правильно помню (это легко уточнить), то те виды исследований, которые вы перечислили, появились именно по результатам устранения замечаний.
npoechelon, я неоднократно пробовал в деле и АК-ВС, и АК-ВС 2. Вы думаете, что у меня ещё осталась надежда, что у вашей компании есть мотивация делать качественные продукты? Единственная ваша цель — не допустить распространения в отрасли сертификации PVS-Studio и средств анализа путём формального выполнения требования использования статического анализа. В качестве вы не заинтересованы.facet
12.01.2017 18:05Уважаемый, asasasdd!
По вашему тексту можно изучать методы геббельсовской пропаганды. Здесь есть и явная ложь («появились именно по результатам устранения замечаний»), и попытки манипулировать («Все, кто работает… прекрасно знает», «Старый добрый принцип…»), и отсутствие конкретики («работает также некорректно, но чуть лучше»), и попытки сталкивать с третьей стороной («ваша цель — не допустить распространения в отрасли сертификации…»), ну и, конечно, перевод на параллельные темы и масса эмоций (в основном обиды). Короче, характерно выделяющийся профиль.
Так как дискуссия перестает быть конструктивной, этот ответ вам будет заключительным.
Теперь по пунктам.
Относительно ГОСТ Р 56939-2016, который вы связали с обсуждаемой темой.
По поводу исследований, которые с ваших слов появились после замечаний, вот первый вариант стандарта, в котором они все есть, так как были изначально: http://docs.cntd.ru/document/1200113247
Cмотреть нужно 13-16 стр. asasasdd, ЛГАТЬ – это очень плохо.
Ликбез. Разумеется, ГОСТ изначально не был копией РД НДВ и не задумывался таковым. Извините, ну уж даже не знать, что упоминаемый статический анализ в РД и в ГОСТ – это абсолютно разные понятия?! Да уж.
Идея РД НДВ в декомпозиционном подходе к разбору структуры текста программы (там вопросы безопасности косвенно возникают лишь тогда, когда речь идет о защите гостайны уровня аж СС!). Это поймет любой начинающий программист.
ГОСТ Р 56939-2016 – это (для справки) организационный стандарт, который в том числе включает в себя совокупность мер, которые может обоснованно принять разработчик ПО с целью повышения безопасности программного изделия в рамках именно его жизненного цикла! Здесь, пардон, преследуются другие цели: разработчики стремятся минимизировать риски появления ошибок безопасности, уязвимостей, угроз (связанных их наличием) и т.п. Иные и задачи, и предметная область, и методическая база.
Относительно АК-ВС, который вы подтянули к обсуждаемой теме:
Есть старый анекдот:
— Таки мне Каррузо не понравился: каатавит, гнусавит, в ноты не попадает…
— Вы были на концерте Карузо?
— Нет, мне дгуг по телефону напел.
asasasdd, вы легально используете АК-ВС 2.0 на своем месте работы, и у вас есть конкретные замечания по целевой работе этого продукта? Вы о них сообщили в техподдержку? Разработчики не отреагировали? Номера ваших обращений в техподдержку? Все, как в анекдоте.
Мы признательны всем за конструктивные конкретные замечания и предложения по улучшению продукта, чему и посвящен данный пост.
vovochkin
11.01.2017 16:38+6Спасибо за еще один продукт синтаксического анализа! Я опробовал его, кратко поделюсь впечатлениями.
User Interface: красиво:) Запускаешь серверную часть, идешь в браузер — создаешь проект. И тут — неудобство:Для С/C++ проектов требуется дополнительная конфигурация.
Я понимаю, почему это сделано, но запускать утилиту, которая мониторит системные вызовы — не всегда удобно.
На большом проекте, использующем Qt и сторонние библиотеки, утилита сдохла. bad_alloc и падение без каких-либо полезных результатов. Уже минус, т.к. проверять планировал именно его.
Открыт древний и большой проект, не использующий ничего и написанный на Си с классами:)
Продукт нашел всего 4 дефекта трех типов, которые, признаюсь, действительно выглядят странно:
- присвоение переменной самой себе
tmp = tmp;
- всегда истинное выражение
if ( arr[i]!='+' || arr[i]!=' ' )
- неконтролируемая рекурсия
ISuperStringStream& MySuperStringStream::operator<<(signed char v) { return operator<<((char)v) ; }
При этом параллельно работал CppCheck, который одних только ошибок нашел 37 штук, варнинги и прочие стилистические сообщения я отключил. При этом в коде есть вещи, которые явно указывают на ошибку:
void nps::MyClassEvent::getTextData(MyElement& el) const { el.doSmth(); MyAttributes* attr = new MyAttributes() ; attr->insert("t0") ; }
У меня есть подозрение, что AppChecker анализирует не все файлы и файл с проектом сформировался криво, но как это быстро проверить и исправить, я не знаю.
Возможно, я что-то делаю не так, однако для быстрой проверки CppCheck и прочие Clang Static Analyzer'ы лично мне подходят удобнее.
Я допускаю, что ваш продукт можно правильно настроить и он будет работать превосходно, но, например, ручное формирование и загрузка специально сохраненного файла — как-то это долго и лениво.
Andrey2008
11.01.2017 16:54+7Ради интереса, прошу ещё попробовать PVS-Studio. Выдам ключ на неделю (напишите мне на karpov [@] viva64.com), если демонстрационной версии покажется мало. И прошу написать о результатах.
vovochkin
11.01.2017 21:49+13Попробовал и понял, что сравнение в пользу PVS-Studio.
Проверял я на standalone-приложении. Отпишу кратко впечатления от первого запуска. При первом запуске увидел отличнуюкартинку:Andrey2008
11.01.2017 22:10+1Большое спасибо за эксперимент и подробный комментарий. Попробуем понять, что там не так с Settings.xml. По этому вопросу, возможно, кто-то из моих коллег напишет Вам личное письмо и уточнит детали.
Касательно ложного срабатывания. В PVS-Studio есть множество механизмов для их подавления. В данном случае, лучше всего написать комментарий:
//-V:LOG_ERROR:V672
Комментарий рационально написать рядом с объявлением макроса. Тогда комментарий будет воздействовать на весь код, где используется этот макрос. Есть и другие способы. Подробности можно посмотреть в документации.
Ещё раз спасибо.
P.S. Да, если кому-то интересны графики и т.п., напоминаю, что PVS-Studio умеет интегрироваться с SonarQube.
staticlab
11.01.2017 22:55+1Андрей, а у вас нет какого-нибудь не очень большого забагованного проекта для экспериментов? Хочу на выходных попробовать сравнить PVS-Studio, AppChecker, Clang, CppCheck и может быть что-нибудь ещё доступное.
Andrey2008
11.01.2017 23:28+2Задача не простая. По опыту знаю, что бывает непросто найти небольшой интересный проект, который в добавок одновременно адекватно проверится несколькими анализаторами. То кто-то отвалится, то кто-то подведёт и из-за какого-то макроса выдаст слишком много ложных срабатываний. Эти ложные срабатывания можно убрать, но они портят картину, если хочется указать количество ложных срабатываний. Не анализатор плох, а не повезло. А другому не повезёт на другом проекте. :)
На вскидку, предлагаю взять проект WinMerge. Но не потому, что он очень забагован :). Просто проект небольшой и должен относительно легко проверяться (правда не знаю, что делать с Clang). Мы про него уже пару раз писали (в 2010 и 2012 году). Но только надо брать старую версию проекта (скажем конца 2009 года), когда до него ещё не добрался ни PVS-Studio, ни Cppcheck.
Что ещё… Вот есть такой проект Torque2D. Я его пару месяцев назад быстренько проверил, увидел, что есть ошибки, но не добрался до полноценной проверки и написания статьи. Можно на нём попробовать.
staticlab
11.01.2017 22:50Странно, что у вас cppcheck ничего не нашёл.
$ cppcheck bugs.cpp [bugs.cpp:21]: (error) Uninitialized variable: a
Clang так же остался недоволен:
$ g++ -Wall -Wextra -pedantic -Werror -O3 -c bugs.cpp bugs.cpp:21:5: error: variable 'a' is uninitialized when used here [-Werror,-Wuninitialized] a->bar(); ^ bugs.cpp:20:9: note: initialize the variable 'a' to silence this warning A* a; ^ = NULL 1 error generated.
vovochkin
12.01.2017 07:46+3Вы правы, CppCheck всё нашел. Было уже поздно и я проверял файл, в котором этих ошибок еще не было:( В этом плюс AppChecker'а и PVS-Studio: там что ты компилируешь, то и проверяешь.
Тем не менее, AppChecker ничего подозрительного не нашел в этом коде.
facet
12.01.2017 14:28Да, Вы правы, использовать standalone-приложение конечно приятнее. Но для этого необходимо, чтобы оно было на той же машине, на которой производится сборка проекта, а это не всегда удобно и даже не всегда реально — из-за различий операционных систем и даже архитектур процессора. Особенно, если аудит кода проводит не разработчик, а специалист по QA, ИБ и т.п.
mayorovp
12.01.2017 14:32+2Вот только PVS-Studio умеет запускаться по-разному, а AppChecker — только через одно место.
vovochkin
12.01.2017 14:59+4А как аудит кода проводят вышеозначенные специалисты?
Насколько я понимаю, им тоже придется запустить сборку проекта, чтобы гарантировать соответствие исходников и бинарных файлов. Или там другие продукты используются?staticlab
12.01.2017 15:28По идее же, если отчёт был получен с сервера CI, то будет известен коммит, для которого выполнялся анализ. Этот коммит аналитик у себя и зачекаутит.
vovochkin
12.01.2017 15:35Поддержка CI (Jenkins, TeamCity) также есть, но в альфа-версии
Я не заметил этот комментарий от разработчиков, а сейчас AppChecker на такое не очень способен (по крайней мере, доступная для скачивания версия).
facet
12.01.2017 14:27Спасибо за предоставленный отзыв! Как с вами можно напрямую связаться, чтобы получить более подробную информацию для разрешения возникших сложностей?
Относительно результатов тестов, то похоже действительно проанализировались не все исходники, поскольку те дефекты, которые нашел pvs и о которых Вы пишете в своем комментарии, AppChecker также обнаруживает)
В частности:
V570 The 'Parabola' variable is assigned to itself. SomeFileName.cpp 287
Parabola =Parabola ;
Это тот же тип дефекта, что и нашелся у Вас:
присвоение переменной самой себе
tmp = tmp;
Относительно V522 Dereferencing of the null pointer 'SetterGetter' might take place. OtherFileName.cpp 305
if ( SetterGetter==0 ) { SetterGetter->set(false) ; }
об этом типе дефекта собственно сама наша статья) было бы подозрительно, если бы мы писали о таком дефекте и при этом его не обнаруживали)vovochkin
12.01.2017 14:57+2Да, я сам удивился, что дефект не найден — и поэтому решил сделать специальный пример. Удалось ли проверить этот тест из комментария выше?
Я работаю из под QtCreator, pro-файл имеетследующий вид:TEMPLATE = app CONFIG += console CONFIG -= app_bundle CONFIG -= qt SOURCES += main.cpp
- присвоение переменной самой себе
AllexIn
Разжевывание совсем уж для детей.
npoechelon
Рассмотренные проекты явно не детьми разрабатываются, а ошибки такие допускаются…
andreymal
Но не потому что не знают, что это такое, а по невнимательности.
В том числе поэтому языки, не имеющие NULL, рулят)
npoechelon
так поэтому мы разрабатываем наше решение AppChecker. На нашем сайте можно заполнить форму и получить лайт версию.
aragaer
Никогда не понимал до конца вот это вот «в языке есть NULL, поэтому это плохо» — NULL это просто ноль. Или какое-то другое значение. Почему если есть возможность присводить какое-то значение в какую-то переменную, то сразу язык от этого портится?
andreymal
NULL — это не просто ноль, а нулевой указатель. И плохо это как раз тем, что к нему можно случайно обратиться и программа случайно упадёт (или не упадёт, что ещё хуже, потому что ошибку никто не заметит, а потом она вылезет лет через двадцать на ближайшей к вам атомной электростанции :). И эти обращения в мейнстримовых языках не проверяются во время компиляции, поэтому над ними приходится городить костыли в виде этих самых статических анализаторов
aragaer
С тем же успехом можно разыменовать любой другой указатель (например мой любимый — 5). Указатель это число, некоторый адрес в памяти. Он может принимать очень много значений и очень немногие из них будут соответствовать расположенным в этой памяти объектам нужного типа. NULL это только одно из некорректных значений. Просто оно очень удобно для обозначения «на самом деле тут ничего нет». Все равно, это лучше, чем если бы был указатель на объект, который уже удален, но зато не NULL.
andreymal
Ответ почти аналогичный: в том числе поэтому языки с указателями это плохо)
sand14
Интересно, что в статически типизированных языках без использования unsafe-кода нельзя в ссылочную переменную записать недействительное значение указателя, кроме нулевого.
Чтобы обойти статические проверки компилятора, даже придумали для нуля ключевое слово null.
Интересно, можно ли было обойтись без null.
andreymal
Без явной проверки на наличие объекта обратиться к нему в Rust никак нельзя,
obj.getName()
не скомпилируется, только илиmatch
, илиif let
, илиobj.unwrap().getName()
, если есть уверенность, что объект действительно есть (а если его таки не окажется, то на unwrap программа упадёт с внятным сообщением об ошибке, а не с неопределённым поведением как в C/C++)А просто
let obj: MyClass = чтототам
будет содержать рабочий объект гарантированно и в таком случае будет можноobj.getName()
Barafu
Смотрите шире: просто не надо писать на С++ то, что можно писать не на С++. Я Rust не знаю, но приведённый пример вызывает уныние: это что, при каждом обращении к свойству объекта необходимо вручную писать код, что делать, если объекта нет? Извините, но это просто слишком. Если писать код не для спутника или ядерной ракеты, то это просто безумный расход труда на перестраховки.
staticlab
А если бы это был C++?
andreymal
Зачем при каждом-то
Или, как вариант
Капитан Очевидность замечает, что если объекта нет, то и обращаться к нему нельзя. Причём вы ДОЛЖНЫ проверить, есть объект или нет, вообще на ЛЮБОМ языке программирования, ОСОБЕННО на C/C++ :)
Sixshaman
Так ведь наоборот всё, гораздо лучше, если приложение падает там где должно, разве нет?
Простейший пример: функция загрузки какого-либо объекта из файла, если файла нет или он повреждён — возвращается NULL. Естественная абстракция.
Без NULL необходимо вводить специальный экземпляр «невалидного объекта», на который после вызова функции следует проверять возвращённое значение. Проверка такая же, только теперь уже анализатор под это не напишешь. Более того, приложение начнёт работать как ни в чём не бывало, если эту проверку пропустить. В итоге этот-то баг как раз и просочится на электростанцию и вылезет через 20 лет, а не будет обнаружен на тестировании.
Разве не так всё?
andreymal
Так с NULL оно может или падать, или не падать — как повезёт. На тестировании не упадёт, а на атомной станции через 20 лет сложится такая сильно специфическая ситуация, что оно возьмёт да упадёт, кто знает. Или наоборот: на тестировании будет падать и на это будет расчёт (хотя зачем так вообще делать?), а на станции возьмёт и не упадёт.
Языки, в которых эту самую проверку пропустить нельзя, рулят) Специальный экземпляр «невалидного объекта» должен быть таким, чтобы его нельзя было не проверить. Тот пример на Rust, что я кинул выше, подходит и для этого случая с файлом. Анализ там проходит прямо в процессе компиляции и никаких проблем нет и быть не может)
Кстати, за это я не люблю активно пиарившийся тут Go: там проверку пропустить можно (
if err != nil
, вот это вот всё), и это считается нормой. В Rust пропустить проверку нельзя — не скомпилируется.ainoneko
andreymal
Может и nullptr, в контексте данной ветки всё равно не суть)
Хотя гугл намекает, что в C такого нет
sand14
Потому что NULL это ноль не в абстрактной целочисленной переменной, а в переменной, которая трактуется как указатель на объект (или на на ту же целочисленную переменную).
Но принята «конвенция», что в памяти по адресу ноль не может быть объекта/переменной.
Именно поэтому разыменование нулевого указателя (или обращение с полям/методам переменной ссылочного типа) приводит в лучшем случае Null Reference/Pointer Exception, в худшем — к Undefined Behaviour.
aragaer
Интересно, никогда раньше не слышал о такой «конвенции». Гугл ничего явного не подсказал, или я что-то не то искал. Зато я узнал, что в Линуксе нулевая страница адресного пространства просто всегда явно маппится без прав доступа, поэтому происходит segfault.
В «особых случаях» нулевой адрес является вполне себе валидной штукой — примеры опять же можно найти в гугле.
Под рукой нет Кернигана-Ритчи, но насколько я помню, разыменование указателя, который не содержит адрес объекта того типа, на который ссылается этот указатель, это Undefined Behavior. Ни о каком особом статусе нулевого адреса я не помню. Может просто невнимательно читал.
Все эти фокусы с указателями, разыменовываниями и прочим могут выглядеть как игра с огнем или чем-то более опасным, но если просто оперировать памятью, структурами и массивами, то оно все выглядит вполне естественным. Выделил память, передал в функцию адрес этой памяти, записал по нужному смещению нужное значение. Никакой магии, все на виду.
aragaer
А вот нашел C99. Там все написано:
Теперь я буду знать, что у нулевого адреса и нулевого указателя действительно особый статус, определенный стандартом.
mayorovp
Не совсем так. В стандарте нет требования, чтобы нулевой указатель указывал на нулевой адрес. На нестандартных архитектурах или компиляторах он может указывать, к примеру, на 0xffffffff.
aragaer
В стандарте есть требование, что константа 0 это нулевой указатель. Про адрес тут речи нет. Кроме того, есть требование, что любые два нулевых указателя равны. Значит никаких других нулевых указателей быть не должно. 0xffffffff это не нулевой указатель. Просто особый невалидный.
mayorovp
В стандарте нет требования, чтобы нулевые указатели в понимании разных компиляторов совпадали. Если на некоторой платформе все нулевые указатели равны 0xffffffff — это не будет нарушением стандарта.
aragaer
Если при этом выполняется условие «константа 0 является нулевым указателем» — вопросов нет. Но выглядит это странно.
Mingun
Так в станарте не сказано, что битовое представление константы 0 и нулевого указателя должно совпадать. Это в коде вы пишите
а машина выполняет
Никаких противоречий, хоть и непривычно.
mayorovp
Нет, не так.
(void*)xxx
будет указателем на нулевой адрес. К нулевому указателю приводится только константа 0.Mingun
Ну в общем да. Изначально я писал пример с приводом
(void*)0
, но потом мне показалось нелогичным, что в "точке зрения компилятора" используется какой-то необъявленныйxxx
и я решил его явно указать. Исправлять потом было поздно :). Но логика, я думаю, понятнаsand14
Верно, особый статус, т.к. понятие указателя несет определенную семантику, в отличие от «просто» числа
И выше вам верно отметили, что NULL это необязательно 0, может быть и "-1" (все биты единичные)
Даже в WinAPI, функции, возвращающие хендлы (те же указатели), в качестве невалидного указателя, через одну возвращают то 0, то -1.
Nakosika
Сложность возрастает. Нужно писать больше if для одного и того же, потому что внезапно значение вместо юзернейм пришёл нул. Особенную пикантность добавляет то, что в типизированных языках обычно нет разделение на тип который может принимать нул и тип который не может. Приходится пилить костыли, как это сделано в восьмой яве — Optional. Но эти костыли на то и костыли что спасают только от части проблем.
ArRnorets
Причина не имеет значения, ключевое слово «допускаются». А главное, попробуйте потом объяснить, что «я просто просмотрел» персоналу ближайшей атомной электростанции :)
С утверждением о языках, не имеющих NULL, категорически согласен :)
Andrey2008
Кстати, предлагаю свою статью, для тек хочет пофилософствовать о более интересном и экзотическом случае. Ведь иногда бывает, что разыменование вроде как есть и вроде как его нет :)