- PVSM.RU - https://www.pvsm.ru -
Сразу хочу обратить внимание читателей, что эта статья является переводом и я, как разработчик конкурирующего продукта PVS-Studio, воздержусь от собственных оценок ситуации.
Будучи общепризнанными лидерами и вдохновителями индустрии статического анализа, мы польщены тем, что другие компании ориентируются на наш продукт как на эталон качества при разработке своих инструментов. Обычно мы не считаем нужным как-либо реагировать на публикации о результатах сравнений нашего анализатора с другими продуктами, однако «экспертный отчет», выпущенный компанией Grammatech и посвященный сравнению инструментов CodeSonar и PC-lint, оказался крайне неприятным исключением. Вместо того чтобы сосредоточиться на достоинствах своего продукта, авторы этого документа прибегли к ложным заявлениям в адрес PC-lint и искажению фактов относительно его технических возможностей, что, вероятно, явилось следствием давления со стороны рынка, и мы считаем своим долгом ответить на эту ложь, рассказав о реальном положении дел.
PC-lint — это эффективный и уважаемый среди разработчиков инструмент статического анализа кода на C и C++. Он был создан компанией Gimpel Software в 1985 году и с тех пор непрерывно развивается. В течение всех этих 30 лет PC-lint лидировал в данной отрасли, предлагая пользователям инновационные возможности, например, механизм отслеживания данных при их перемещении между функциями и модулями программы, строгую проверку типов и анализ размерностей, а также поддержку пользовательских функций. PC-lint пользуется доверием десятков тысяч разработчиков, экспертов технического контроля, тестеров и экспертов-криминалистов; поддерживает десятки компиляторов и платформ и предлагает целый ряд дополнительных опций. PC-lint применяется повсеместно практически в каждой отрасли, включая области с повышенными требованиями к безопасности, такие как медицина и автомобилестроение.
Экспертный отчет под заголовком «How CodeSonar Compares To PC-lint (And Similar Tools)» («Сравнение CodeSonar с PC-lint (и другими подобными инструментами)»), доступен на сайте Grammatech. Этот документ претендует на достоверное изложение результатов сравнения инструментов CodeSonar и PC-lint (в нем также упоминаются другие анализаторы, но основной акцент делается на PC-lint), однако в действительности представляет собой не более чем набор своекорыстных, ложных утверждений, не подкрепленных реальными фактами и призванных ввести читателей в заблуждение. На основании этих ложных утверждений авторы отчета пытаются представить продукт CodeSonar в выгодном свете за счет PC-lint.
В попытке очернить PC-lint авторы документа прибегают к определенным тактическим приемам, а именно:
Рассмотрению и опровержению этих утверждений будут посвящены два раздела данной статьи. В разделе «Обвинения» мы изучим ключевые положения отчета, большинство из которых не подкреплены никаким доказательствами, и предоставим факты. В разделе «Искажение фактов на примерах» мы рассмотрим использованные в отчете примеры кода с ошибками, которые, по заявлению авторов, не могут быть обнаружены с помощью PC-lint, и покажем настоящие диагностические сообщения нашего инструмента с результатами анализа этих фрагментов. В отчете также содержится ряд обоснованных критических замечаний — их мы рассмотрим в соответствующем разделе.
В отчете Grammatech предлагается ряд довольно расплывчатых и крайне неточных утверждений, например:
Хотя мы согласны с тем, что оригинальный «lint» в Unix был весьма примитивен, попытка приписать нашему продукту это же качество только на основании схожего названия выглядит в лучшем случае неискренне. Более 30 лет Gimpel Software лидировали в области статического анализа, а PC-lint способствовал многим техническим достижениям в течение этого времени.
Здесь мы видим очередную попытку смешать PC-lint с теми самыми «инструментами первых поколений», а также высокомерное заявление, будто задачи PC-lint «намного скромнее». Первоочередная задача PC-lint — это поиск программных ошибок как в малых, так и в больших проектах, включая «настоящие» ошибки вроде переполнения буфера, выхода за границы массива, логических ошибок и неопределенного поведения. Мы также ставим своей целью удовлетворение самых разнообразных запросов наших клиентов, чьи потребности превышают возможности многих конкурентов. К таким запросам относятся поддержка различных стандартов MISRA, строгий контроль типов, поддержка пользовательской семантики и так далее. Понимая, что ни один инструмент в принципе не может эффективно находить все типы ошибок, мы ставим перед собой более высокие цели. PC-lint стремится не просто находить серьезные дефекты, а выявлять приемы программирования, приводящие к их появлению. Неправильно полагать, что широкий спектр возможностей PC-lint означает неспособность обнаруживать сложные ошибки.
И снова данное утверждение может быть справедливым в отношении оригинального lint, но никак не в отношении PC-lint, и, подразумевая такую преемственность, авторы отчета ведут себя лицемерно и обманывают читателей.
Далее, авторы приводят несколько примеров ошибок, связанных с передачей данных между функциями, и утверждают, что PC-lint не умеет находить ни одну из них (хотя на самом деле он находит почти все эти ошибки, а также некоторые, не упомянутые в отчете), и заявляют следующее:
Данное утверждение начинается с ложной предпосылки, будто PC-lint во время испытаний не смог обнаружить рассмотренные в отчете ошибки, после чего авторы перечисляют несколько уникальных «приемов», используемых их инструментом, хотя в действительности PC-lint использует те же механизмы, причем некоторые из них были реализованы еще до появления CodeSonar, вопреки заявлению о том, что их не найти «ни в одном примитивном анализаторе».
Говоря о пользовательском интерфейсе, авторы утверждают следующее:
Прежде всего, следует отметить, что PC-lint имеет очень гибкие настройки формата вывода и по умолчанию поддерживает текстовый, HTML и XML-форматы. Что касается графических интерфейсов, вместе с самим анализатором PC-lint пользователи получают и необходимые инструменты для его интеграции с существующими приложениями. Так, мы предоставляем конфигурации для многих популярных сред разработки; кроме того, существует ряд сторонних организаций, которые разрабатывают серьезные, полноценные решения для интеграции с такими средами разработки, как Visual Studio и Eclipse.
Отчет завершается следующим выводом:
Как и почти во всем остальном тексте отчета, ни в одном из трех утверждений процитированного отрывка не содержится и доли правды. Это абсолютный вымысел, основанный на предшествующих заведомо ложных тезисах.
Представленные в отчете примеры зачастую неполны, что, вероятно, обусловлено их демонстрационным характером, и потому не позволяют провести объективное сравнение продуктов или подтвердить заявления Grammartech. По этой причине авторы отчета «подправили» большинство использованных примеров так, чтобы они выглядели как законченные, самодостаточные фрагменты кода (как, например, на нашей демонстрационной странице Online Demo [1]). Для этого они помещают блоки кода внутрь функций, объявляют изначально не определенные типы и функции, исправляют опечатки и так далее. Во всех случаях эти изменения никак не сказываются на семантике кода или способности PC-lint обнаруживать искомую ошибку, но лишь облегчают задачу по воспроизведению тех же результатов другими инструментами.
void test_buffer_overrun(int p[]) {
p[4] = 1729;
}
void test_driver(void) {
int test[4];
test_buffer_overrun(test);
}
В отношении данного фрагмента в отчете говорится следующее:
PC-lint не может диагностировать эту ошибку, поскольку не умеет отслеживать путь прохождения данных через границы процедур.
Это самая обыкновенная ложь. Механизм отслеживания данных при их перемещении между функциями был реализован в PC-lint пятнадцать лет назад, тогда как в отчете его наличие отрицается. Чтобы пользователь мог найти баланс между потребностями проекта и доступными аппаратными ресурсами, PC-lint использует «многопроходную» модель анализа, позволяющую задавать нужную глубину поиска данного вида ошибок. По умолчанию глубина поиска равна 1, в то время как для диагностики большинства проблем, связанных с отношениями между функциями, требуется глубина поиска 2. Подробную информацию о работе данного механизма можно найти в руководстве пользователя PC-lint, а также на нашем официальном сайте и демонстрационной странице Online Demo. Если запустить PC-lint с ключом -passes=2 (в примерах на Online Demo он прописывается автоматически), будут получены следующие результаты:
During Specific Walk:
line 7: test_buffer_overrun([4]) #1
2 Warning 415: Likely access of out-of-bounds pointer
(1 beyond end of data) by operator '['
[Reference: file ipa2.c: lines 2, 7]
2 Info 831: Reference cited in prior message
7 Info 831: Reference cited in prior message
Сообщение N415 предупреждает об искомом переполнении, заодно указывая, как далеко за пределами массива оно возникло, а также исполнение каких участков кода привело к ошибке. Последние два сообщения (N831) факультативны и используются для вывода текста предупреждения в стандартизированном формате, который может быть распознан средами разработки и прочими приложениями. В последующих примерах сообщения N831 отключены (через параметр -e831) в целях экономии места, поскольку та же самая информация уже включена в основное сообщение.
typedef unsigned long size_t;
void* malloc(size_t);
void test_buffer_overrun(int p[]) {
p[4] = 1729;
}
void test_driver(void) {
int *p = malloc(4);
test_buffer_overrun(p);
}
Как и в предыдущем случае, в этом примере неверно утверждается, что PC-lint неспособен найти ошибку:
PC-lint не умеет находить такие ошибки по той же причине, по какой он не умеет находить переполнения статически выделяемых буферов, как в предыдущем примере.
Проверка данного кода с помощью PC-lint с параметром -passes=2 дает следующий результат:
During Specific Walk:
line 10: test_buffer_overrun([1]? | 0?) #1
5 Warning 662: Possible creation of out-of-bounds pointer
(4 beyond end of data) by operator '['
[Reference: file ipa3.c: lines 5, 9, 10]
During Specific Walk:
line 10: test_buffer_overrun([1]? | 0?) #1
5 Warning 613: Possible use of null pointer 'p' in
left argument to operator '['
[Reference: file ipa3.c: lines 9, 10]
During Specific Walk:
line 10: test_buffer_overrun([1]? | 0?) #1
5 Warning 661: Possible access of out-of-bounds pointer
(4 beyond end of data) by operator '['
[Reference: file ipa3.c: lines 5, 9, 10]
PC-lint находит как место создания указателя, указывающего за границы буфера, так и место его использования, а также проверяет этот указатель на значение null (функция malloc может вернуть null, а в примере эта возможность не проверяется).
Подробное описание вызова test_buffer_overrun([1]? | 0?) #1, предваряющее текст предупреждения, показывает путь исполнения кода перед появлением сообщения. В данном случае мы рассматриваем вызов функции test_buffer_overrun, в котором передается указатель, указывающий либо на массив из одного элемента ([1]?, например, из одного значения типа int), либо является нулевым указателем (0?). Вопросительный знак означает, что неизвестно, какой из этих двух вариантов имеет место на самом деле, поскольку значение не было проверено на null. Таким образом, PC-lint не просто диагностирует проблему — он объясняет, как именно пришел к тому или иному заключению.
#define NULL (void *)0
void test_deref(int *p) {
*p = 55;
}
void test_driver(void) {
int *pi1 = NULL;
test_deref(pi1);
}
И снова авторы отчета заявляют, будто приведенный пример PC-lint не по силам:
Это, пожалуй, самый простой пример разыменовывания нулевого указателя с использованием двух процедур. Только CodeSonar может находить такие ошибки.
И опять это утверждение можно опровергнуть, включив параметр -passes=2:
During Specific Walk:
File ipa4.c line 9: test_deref(0) #1
4 Warning 413: Likely use of null pointer 'p' in
argument to operator 'unary *'
[Reference: file ipa4.c: lines 8, 9]
PC-lint выдаст предупреждение о разыменовывании нулевого указателя и объяснит, как и почему оно происходит.
typedef unsigned long size_t;
void *malloc(size_t);
void free(void *);
void test_free(int *p, int x) {
if (p && x < 10)
free(p);
}
void test_driver(void) {
int *pi1 = malloc(20);
test_free(pi1, 20);
}
В отношении этого примера в отчете утверждается следующее:
В данном примере буфер выделяется в одной процедуре, а освобождается в другой — но только при выполнении определенного условия. Эта ошибка может быть найдена только с помощью CodeSonar.
Однако, запустив PC-lint с параметром -passes=2, мы увидим, что это не так:
During Specific Walk:
line 11: test_free([5]? | 0?, 20) #1
8 Warning 429: Custodial pointer 'p' (line 5) has not been freed or
returned
PC-lint смог обнаружить и эту ошибку, а также выдать подробную сводку о вызове, спровоцировавшем предупреждение.
У каждого инструмента есть сильные и слабые стороны, и, если знать о недостатках конкретного инструмента, не составит труда придумать искусственные примеры, чтобы их подчеркнуть. В отчете можно найти несколько очень старательно сконструированных примеров кода, эксплуатирующих реальные, хотя и хорошо известные, недостатки PC-lint. Большинство из этих примеров выявляют ограничения в способности PC-lint отслеживать данные, связанные с указателями. Система отслеживания данных была доработана в PC-lint Plus (следующий шаг в развитии PC-lint; на данный момент приложение находится в стадии бета-тестирования), и указанные ограничения были устранены. Примеры ниже не диагностируются PC-lint, однако мы приведем результаты их анализа с помощью PC-lint Plus, чтобы показать, что мы непрерывно работаем над улучшением нашего продукта.
int foo() {
int iret;
int *p = &iret;
return iret;
}
Сообщение PC-Lint Plus:
4 warning 530: likely using an uninitialized value
return iret;
^
2 supplemental 891: allocated here
int iret;
^
typedef unsigned long size_t;
void *malloc(size_t);
void free(void *);
void foo() {
char *p = (char *)malloc(10);
char *q = p;
if (p) {
p[0] = 'X';
free(p);
q[0] = 'Y';
}
}
Сообщение PC-lint Plus:
11 warning 449: memory was likely previously deallocated
q[0] = 'Y';
^
10 supplemental 891: deallocated here
free(p);
^
6 supplemental 891: allocated here
char *p = (char *)malloc(10);
^
typedef unsigned long size_t;
void *malloc(size_t);
void free(void *);
void test_double_free(int *p) {
if (p)
free(p);
}
void test_driver(void) {
int *pi1 = (int *)malloc(sizeof(int));
if (pi1)
test_double_free(pi1);
if (pi1)
free(pi1);
}
Сообщение PC-lint Plus:
15 warning 2432: memory was potentially deallocated
free(pi1);
^
15 supplemental 894: during specific walk free([4]@0/1)
free(pi1);
^
7 supplemental 891: deallocated here
free(p);
^
11 supplemental 891: allocated here
int *pi1 = (int *)malloc(sizeof(int));
^
void foo() {
char buffer[10];
char *pc;
pc = buffer;
for (int i = 0; i <= 10; i++)
*pc++ = 'X';
}
Данный пример демонстрирует переполнение буфера в цикле for. Используемые в PC-lint и PC-lint Plus модели для отслеживания состояний значений (пока) не учитывают отношения между i и pc в этом коде. На данный момент это объективный недостаток PC-lint. Мы могли бы с легкостью придумать аналогичный пример, чтобы подчеркнуть слабые стороны CodeSonar, но это ничего бы нам не дало. Как уже говорилось выше, мы признаем, что у каждого инструмента есть свои преимущества и недостатки и что каждый инструмент может диагностировать ошибки, невидимые для остальных. Вместо того чтобы указывать на недостатки других анализаторов, мы предпочитаем работать над достоинствами PC-lint и непрерывно улучшать наш продукт, чтобы он отвечал потребностям пользователей.
В таблице ниже мы собрали ключевые ложные утверждения Grammatech относительно PC-lint и опровергающие их факты с нашей стороны.
Ложное утверждение | На самом деле |
PC-lint — это примитивный инструмент из семейства оригинального lint в Unix. | PC-lint — это передовой статический анализатор, который непрерывно и независимо от других инструментов развивается и совершенствуется на протяжении последних 30 лет, предлагая инновационные, отмеченные наградами средства анализа. Одно из них — система отслеживания данных при их передаче между функциями и модулями. |
PC-lint может обнаруживать только самые очевидные ошибки. | PC-lint использует целый ряд передовых технологий, что позволяет ему обнаруживать сложные ошибки, в том числе ошибки из примеров в отчете Grammartech |
PC-lint не предназначен для поиска серьезных ошибок в больших проектах. | PC-lint успешно применяется на проектах любого размера, от сотен строк кода до миллионов. |
PC-lint поддерживает только текстовый формат вывода и не приспособлен для использования с инструментами непрерывной интеграции. | PC-lint поддерживает практически любой формат отчета, включая простой текст, HTML и XML, и, как показывает опыт наших клиентов, может применяться самыми разными способами в связке с другими приложениями, в том числе инструментами непрерывной интеграции, такими как Hudson и Jenkins. |
PC-lint не показывает путь исполнения кода, спровоцировавшего предупреждение, при поиске сложных ошибок. | PC-lint предоставляет подробную информацию, где это возможно, включая последовательность вызовов и значений, приведших к тому или иному заключению. |
PC-lint предназначен только для разработчиков. | PC-lint, в соответствии со своим предназначением, используется разработчиками ПО, экспертами по техническому контролю, тестерами и экспертами-криминалистами. |
PC-lint умеет распознавать проблемы только в пределах файла. | PC-lint с самого начала своего существования умеет анализировать программы целиком, в том числе отношения между модулями. Эта особенность, среди прочих, и отличала его от других инструментов. |
PC-lint неспособен найти все возможные программные ошибки. | Учитывая, что ни один статический анализатор не способен диагностировать все ошибки, PC-lint, тем не менее, имеет большой послужной список обнаруживаемых дефектов, включающий множество сложных, реально существующих ошибок, и его возможности продолжают совершенствоваться. |
Gimpel Software приветствует искренние отзывы и конструктивную критику как от наших пользователей, так и от конкурентов, однако заведомо ложные заявления, которые делают авторы рассмотренного отчета, не являются ни искренними, ни конструктивными и не служат интересам программистов или индустрии статического анализа. Политика Grammartech, основанная на ложных и пренебрежительных заявлениях в адрес конкурирующих продуктов, выставляет в невыгодном свете саму эту компанию, а не ее конкурентов.
Как можно заключить из отчета, основные отличия между PC-lint и CodeSonar сводятся к следующему:
Вот хороший пример, почему мы не любим писать про какие-то ни было сравнения анализаторов. Слишком это комплексная задача, где надо одинаково хорошо знать разные инструменты, не быть субъективным и так далее. Я считаю, что хоть сколько-то правдоподобная оценка может быть только при сравнении результатов проверки большого количества проектов разными анализатора. Но это ооочень большая задача с массой нюансов. Все остальные оценки — это только субъективное мнение, которое, как мы здесь видим, легко может перерасти в конфликтную ситуацию.
Автор: PVS-Studio
Источник [2]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/sravnenie/214768
Ссылки в тексте:
[1] Online Demo: http://www.gimpel-online.com/OnlineTesting.html
[2] Источник: https://habrahabr.ru/post/316352/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.