>
>
PVS-Studio и проверка Loki

Андрей Карпов
Статей: 671

PVS-Studio и проверка Loki

В PVS-Studio 3.10 будет существенно улучшена поддержка сложных конструкций, основанных на шаблонах, что позволяет эффективно искать ошибки даже в коде тех программ, где используются сложные шаблонные библиотеки, такие как Loki. Но начнем по порядку.

Не так давно, когда наш продукт для проверки 64-битного кода назывался Viva64, к нам обратился администратор открытой библиотеки Loki*, с предложением проверить, как хорошо она совместима с 64-битными Windows-системами. В этот момент для Windows эта библиотека существовала только в 32-битном варианте. Мы согласились, и, затаив дыхание, приступили к этой задаче. Дело в том, что разработчики компиляторов часто используют библиотеку Loki как эталонный тест, позволяющий определить совместимость со стандартом языка Си++. В ней используются весьма сложные конструкции языка Си++. Мы не были уверены, что успешно сможем ее проанализировать. Мы считаем большим достижением, что наш анализатор не завис на ней, не завершился с критической ошибкой и смог выдать осмысленную диагностику.

Однако результаты диагностики показали существенный недостаток анализатора Viva64. Дело в том, что Viva64 не умеет инстанцировать шаблоны и не может найти в них многие ошибки. Приведем поясняющий пример:

01 template <class T, class M>
02 class TemplateClass
03 {
04 public:
05   char m_char;
06   T *m_t;
07   M m_m;
08   T Get(int index) { return m_t[index]; }
09   void Set(int value) { m_t[m_m] = value; }
10 };
11
12 TemplateClass <char, int> A;

В этом коде обнаруживалась только одна потенциальная ошибка в 8 строке. В этой строке в качестве индекса массива используется переменная типа int, что потенциально опасно при работе с большими массивами данных. При диагностике этой ошибку не имеет значения, что является типом T. А вот две другие ошибки, о которых будет сказано ниже, анализатор Viva64 не обнаружит. Можно сказать, что анализатор Viva64 проверяет код шаблонов достаточно поверхностно и диагностирует только те ошибки, которые в нем присутствуют в независимости, с какими аргументами будет инстанцирован шаблон.

Данный недостаток имеет свои корни в библиотеке OpenCxx, на основе которой была создана библиотека VivaCore, являющаяся основой анализатора Viva64. Причина очень проста - OpenCxx просто не умеет инстанцировать шаблоны. Это смотрится достаточно странно, так как это весьма ограничивает возможности применения библиотеки. Есть правда подозрение, что поддержка инстанцирования шаблонов в библиотеке OpenCxx существовала, но затем была специально удалена, прежде чем проект стал открытым и общедоступным. Об этом косвенно свидетельствуют какие-то странные заглушки и непонятные полупустые классы, связанные с обработкой шаблонов.

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

После реализации механизма инстанцирования, анализатор сообщил нам уже о трех диагностических сообщениях:

Строка 3: error V401: Instantiate TemplateClass < char , int >: The structure's size can be decreased via changing the fields' order. The size can be reduced from 24 to 16 bytes.

Строка 8: error V108: Incorrect index type for "m_t". Use memsize type instead.

Строка 9: error V108: Instantiate TemplateClass < char , int >: Incorrect index type for "m_t". Use memsize type instead.

Встретив в коде строку "TemplateClass A <char, int> A;" анализатор инстанцировал данный шаблон и произвел анализ, уже имея информацию о типах T и M. В результате он сообщил, что структура данных в классе неоптимальна (V401) и размер этого класса на 64-битной системе может быть уменьшен с 24, до 16 байт. Для этого необходимо переупорядочить члены класса. Обратите внимания, что данная диагностика возможна только при знании, какой тип имеют члены. Ведь предупреждения может и не быть, если, скажем, член m_m будут иметь тип size_t. В этом случае переупорядочевание полей не поможет уменьшить размер класса.

Ошибка в строке 8 диагностируется как и раньше, так как знание о типах T и M здесь не имеет здесь значения.

Последняя ошибка в строке 9 также связанна с индексацией массива с использованием переменной типа int. Здесь информация о типе M уже играет важную роль и используется анализатором при работе.

Внесенные усовершенствования дали возможность значительно полнее проверить библиотеку Loki. Более подробно об этой проделанной работе можно будет познакомиться в статье "64-bit Loki", над которой сейчас идет совместная работа нашей команды и администратора библиотеки Rich Sposato.

Анализ Loki мы осуществляли специальной исследовательской версией Viva64. Но теперь решили интегрировать новые возможности в состав новой версии PVS-Studio 3.10 **, которая выйдет в ближайшее время. Пользователям будет доступна новая опция DoTemplateInstantiate, которая включит режим глубокого анализа шаблонов.

*Примечание. Библиотека Loki для языка программирования C++ написана Андреем Александреску как часть книги "Современное проектирование на С++: Обобщенное программирование и прикладные шаблоны проектирования". Библиотека построена на шаблонном метапрограммировании и активно использует возможности языка C++ для обобщённого программирования. (Wikipedia. Loki.)

**Примечание. PVS-Studio - программный продукт, объединивший в себе и расширивший возможности статических анализаторов Viva64 и VivaMP. Нумерация PVS-Studio была начата с версии 3.00, чтобы подчеркнуть, что это эволюционное развитие уже имеющихся инструментов. В версии 3.00 мы не стали спешить с поддержкой инстанцирования шаблонов, а решили реализовать эту возможность в PVS-Studio 3.10.