PVS-Studio

advertisement
О чем надо помнить,
создавая 64-битные приложения
ООО «СиПроВер»
www.viva64.com
Преимущества 64-битных
приложений
• Возможность хранить все
данные в памяти
• Повышение скорости работы
(условие - правильно выбранный
формат данных)
• Повышение скорости работы за
счет архитектурных решений
• Отсутствие затрат на прослойку
WoW64
Различия при программировании
Кто пишет
идеальный
сферический
код?
• Различий нет. Си/Си++ это язык для
разработки кроссплатформенных
программ
• Изменилась только модель данных
• Но на практике, программы не
полностью кроссплатформенны
• Скомпилированная 64-битная
программа != корректно работающая
64-битная программа
Что изменилось?
• Размер указателя: 4 байта -> 8 байт.
• Размер типов size_t, ptrdiff_t, intptr_t,
uintptr_t, INT_PTR, UINTPTR_T: 4 байта -> 8
байт.
• Выравнивание данных. Помните при
сериализации структур.
• Размер индекса массивов.
• Так мало? Этого более чем достаточно для
проблем!
От простого к сложному.
Магические числа
hFileMapping = CreateFileMapping(
(HANDLE) 0xFFFFFFFF, NULL, PAGE_READWRITE,
(DWORD) 0, (DWORD) (szBufIm),
(LPCTSTR) &FileShareNameMap[0]);
//Число 0xFFFFFFFF имеет тип “usigned int”. Правильно:
#define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1)
Хранение указателя в 32-битной
переменной
char *ptr = ...;
int n = (int) ptr;
...
ptr = (char *) n;
Очень неприятная
ошибка.
Может проявляться
только после
длительного времени
работы программы.
Самое важно, что нужно запомнить,
создавая 64-битные приложения
• Указатель, это не тоже самое, что int или long.
Кстати, тип long разный в LP64 и LLP64. это
добавляет путаницы.
• Не смешивайте 32-битные типы и адресную
арифметику. Используйте:
–
–
–
–
–
size_t
ptrdiff_t
intptr_t
uintptr_t
INT_PTR, ….
Более творческое решение для
хранения указателей
int *p1, *p2;
....
char str[128];
sprintf(str, "%X %X", p1, p2);
int *p1, *p2;
sscanf(str, "%X %X", &p1, &p2);
Для печати значений указателей существует “%p”. Часто неправильно
печатают и переменные типа size_t. Следует использовать “%Iu”.
const char *invalidFormat = "%u";
size_t value = SIZE_MAX;
printf(invalidFormat, value);
Ещё о функциях с переменным
количеством аргументов
Неявное приведение типа
unsigned n = it->find("ABC");
if (n != string::npos)
return true;
Адресная арифметика. Знаковые и
беззнаковые типы
float p1[100];
unsigned x = 5;
int y = -1;
float *p2 = p1 + 50;
p2 = p2 + x * y;
// Access violation
*p2 = 1.0f;
Правильный код!!!!!!!!!!!!!!!!!!!!!!!!!!
Адресная арифметика.
Переполнения.
extern int Width, Height, Depth;
size_t GetIndex(int x, int y, int z) {
return z * Width * Height + y * Width + x;
}
...
MyArray[GetIndex(x, y, z)] = 0.0f;
Такие ошибки проявляют себя только на БОЛЬШИХ объемах данных. В
результате, не помогут юнит тесты. Не поможет запуск динамических
анализаторов, таких как Bounds Checker (слишком медленно).
return size_t(z) * Width * Height +
size_t(y) * Width +
x;
О неправильных решениях
return size_t(z * Width * Height + y * Width + x);
return size_t(z) * Width * Height + y * Width + x;
Вечные циклы
P.S. Самое забавное, что
иногда вечный цикл не
возникает. Сказывается
оптимизация, выполняемая
компилятором.
Устаревшие typedef и #ifdef
// Самодельность в одном из файлов
typedef unsigned UINT_PTR;
#ifdef _MY_BUILD_32
// Win32
const unsigned BufferSize = 1024*1024;
#else
// Win16
const unsigned BufferSize = 16*1024;
#endif
Из экзотического: переполнение буфера
Рост размеров структур
struct
{
bool
char
int
};
MyStruct
m_bool;
*m_pointer;
m_int;
struct
{
char
int
bool
};
MyStructOpt
*m_pointer;
m_int;
m_bool;
Другие проблемы
• Использование устаревших функций
(SetClassLong, GetClassLong, GetFileSize,
EnumProcessModules, GlobalMemoryStatus)
• Необъявленные функции в Си
• Различия в параметрах виртуальных функций
• Изменение типа массива
• Указатели в объединениях
• Исключения
• И так далее…
Что поможет подготовить надежную
64-битную версию продукта?
• Юнит-тесты (полагаться только на них
нельзя)
• Регрессионные тесты
• Устранение предупреждений компилятора
• Использование специализированных
инструментов. Например, набор правил
Viva64 в статическом анализаторе кода PVSStudio.
PVS-Studio
• Наборы правил:
– Самый мощный анализ
64-битных ошибок среди
аналогичных инструментов
– Диагностики общего назначения
– Микрооптимизации
– OpenMP
• Об инструменте:
http://www.viva64.com/ru/pvs-studio/
• Скачать:
http://www.viva64.com/ru/pvs-studio-download/
Интеграция с Visual Studio
Интеграция с C++Builder
Полезные ссылки
• Уроки разработки 64-битных приложений
на языке Си/Си++.
http://www.viva64.com/ru/l/
• Статья. Коллекция примеров 64-битных
ошибок в реальных программах.
http://www.viva64.com/ru/a/0065
• Обзоры различных статей
http://www.viva64.com/ru/r/tag/x64/
• База знаний http://www.viva64.com/ru/k/
Download