Новые диагностические возможности, реализованные в PVS-Studio 3.60.
Диагностическое сообщение V303.
В Win64 API присутствует ряд функций, которые присутствуют для совместимости, хотя могут привести к возникновению ошибок в 64-битных программах. Классическим примером является функция SetWindowLong.
LONG SetWindowLong(HWND hWnd, int nIndex, LONG dwNewLong);
Функция SetWindowLong изменяет атрибуты определяемого окна. Функция также устанавливает 32-разрядное значение типа LONG при заданном смещении в дополнительном пространстве памяти об окне. Довольно часто сохраняемыми данными является указатель. В Win32 системах это безопасно, поскольку размер типа LONG совпадает с размером указателя. Однако при перекомпиляции кода для Win64 системы вызов данной функции может привести к ошибке. Рассмотрим код, взятый из реального приложения:
SetWindowLong(window, 0, (LONG)this);
Код корректен с точки зрения системы Win32, но может вызвать ошибку в 64-битном варианте программы. Произойдет ошибка или нет, зависит от того, в какой области памяти создан объект, на который указывает указатель "this". Если объект будет создан за пределами первых 4 гигабайт адресного пространства, то это приведет в дальнейшем к неопределенному поведению программы или ее аварийному завершению. Неприятность данной ошибки заключается в том, что она может проявлять себя редко или через большой промежуток времени программы, когда из-за выделения памяти, объекты начнут создаваться за пределами первых четырех гигабайт.
Исправление кода заключается в использовании нового расширенного варианта функции SetWindowLongPtr, третий параметр которой имеет тип LONG_PTR
Начиная с версии 3.60 анализатор Viva64, входящий в состав PVS-Studio, позволяет быстро найти функции, требующих пристального внимания программиста при разработке 64-битных программ. К таким функциям относятся: SetWindowLong, GetWindowLong, SetClassLong, GetClassLong, GetFileSize и ряд других функций.
Для выявления данных функций предназначено диагностическое сообщение вида: "V303: The function is deprecated in the Win64 system. It is safer to use the NewFOO function". Вместо NewFOO подставляется имя рекомендуемой функции, например "GetFileSizeEx".
Диагностическое сообщение V320.
Ошибки переполнения буфера или его неполной обработкой являются, к сожалению, достаточно частой разновидностью дефектов в программах, составленных на языке Си и Си++. Но нас в данный момент интересует та часть ошибок, которая проявляет себя при переносе приложений на 64-битную систему. Чаще всего подобные ошибки возникают из-за опечаток или из-за неаккуратности программиста. Рассмотрим пример:
STRUCT_1 Abcd;
STRUCT_2 Qwer;
memset(&Abcd, 0, sizeof(Abcd));
memset(&Qwer, 0, sizeof(Abcd));
В данном коде происходит обнуление двух структур. При заполнении второй структуры используется размер первой. В случаи, когда размер первой и второй структуры в 32-битном коде совпадают, то программа будет функционировать корректно. В 64-битной программе размер структур может стать различным, что приведет к сбою.
В ряде случаев анализатор Viva64 позволяет выявить подобные ошибки и предупредить, выдав сообщение " V320: A call of the FOO function will lead to a buffer overflow or underflow in a 64-bit system". Вместо FOO могут будут подставлены имена таких функций, как memset, memcpy, memmove и так далее.
В ряде случаев предупреждение V320 позволит выявить ошибку, которая присутствует как в 64-битном коде, так и в 32-битном, но ранее была не выявлена. Ниже приведен пример ошибки найденный в коде реального приложения в ходе тестирования Viva64:
struct MD5Context
{
unsigned int buf[4];
unsigned int bits[2];
unsigned char in[64];
};
...
MD5Context *ctx;
...
memset(ctx, 0, sizeof(ctx)); //V320
Ошибка заключается в использовании выражения "sizeof(ctx)" вместо "sizeof(*ctx)". Это означает, что как в 32-битной, так и 64-битной версии приложения, будет обнулена только небольшая часть структуры.
Диагностическое сообщение V122.
Данное правило достаточно специфично и в 99% случаев дает ложное срабатывание. Поэтому по умолчанию оно отключено.
Диагностическое сообщение V122 выдается на все memsize-типы (size_t, intptr_t, INT_PTR, DWORD_PTR, указатели и так далее), которые присутствуют в структурах или классах. Наличие в структуре указателя вовсе не означает наличия связанной с этим ошибки. Однако, это означает изменения размера структуры и иногда пользователи хотят просмотреть список всех таких структур.
Приведем пример, где будет выдано сообщение "V122. Memsize type is used in the struct/class":
struct Header
{
unsigned m_version;
size_t m_bodyLen; //V122
};
Диагностические сообщения V2001 и V2002.
Впервые в PVS-Studio появились диагностические правила, не относящиеся к выявлению ошибок в 64-битых или параллельных приложениях. Эти диагностические предупреждения общего назначения созданы по пожеланию наших клиентов. Мы и ранее реализовывали в инструменте PVS-Studio желания клиентов или потенциальных клиентов. Но ранее все эти пожелания касались 64-битности или параллельности.
Думаем, это начало нового этапа развития сотрудничества с нашими пользователями. Мы начинаем не только поставлять и дорабатывать PVS-Studio, но и реализовывать совершенно новые типы диагностических возможностей, интересующих наших пользователей.
Правила V2001 и V2002 достаточно специфичны и скорее всего не будут интересны широкому кругу программистов. Однако надеемся, что вы заметите нашу открытость к сотрудничеству и обратитесь к нам со своими пожеланиями. Мы готовы разрабатывать специализированные расширения PVS-Studio, и даже отдельные решения в области статического анализа кода. За более подробной информацией просим обращаться по почте support@viva64.com или через форму feedback.
P.S. Не забудьте также попробовать функцию "Что это такое?".