Проблемы 64-битного кода в реальных программах: магические константы

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



Вновь хочется рассказать об очередной 64-битной ошибке, найденной нами в одной из программ. Публиковать в блоге интересные и специфичные ошибки программирования для 64-битных систем постепенно становится хорошей традицией, которой мы постараемся следовать.

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

Рассмотрим пример вызова функции CreateFileMapping в одном из приложений:

hFileMapping = CreateFileMapping (
    (HANDLE) 0xFFFFFFFF,
    NULL,
    PAGE_READWRITE,
    (DWORD) 0,
    (DWORD) (szBufIm),
    (LPCTSTR) &FileShareNameMap[0]);

Да, да - вы уже правильно догадались. Ошибка заключается в использовании константы 0xFFFFFFFF. Первый аргумент функции CreateFileMapping может иметь значение INVALID_HANDLE_VALUE, объявленное следующим образом:

#define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1)

В результате INVALID_HANDLE_VALUE действительно совпадает в 32-битной системе со значением 0xFFFFFFFF. А вот в 64-битной системе в функцию CreateFileMapping будет передано значение 0×00000000FFFFFFFF в результате чего система посчитает аргумент некорректным и вернет код ошибки. Причина в том, что значение 0xFFFFFFFF имеет БЕЗЗАНКОВЫЙ тип (unsigned int). Значение 0xFFFFFFFF не помещается в тип int и поэтому является типом unsigned. Это тонкий момент, на который следует обратить внимание при переходе на 64-битные системы. Поясним его на примере:

void foo(void *ptr)
{
  cout << ptr << endl;
}
int _tmain(int, _TCHAR *[])
{
  cout << "-1\t\t";
  foo((void *)-1);
  cout << "0xFFFFFFFF\t";
  foo((void *)0xFFFFFFFF);
}

Результат работы 32-битного варианта программы:

-1              FFFFFFFF
0xFFFFFFFF      FFFFFFFF

Результат работы 64-битного варианта программы:

-1              FFFFFFFFFFFFFFFF
0xFFFFFFFF      00000000FFFFFFFF

Вы спросите, как все это помнить и как быть уверенным, что подобных ловушек не содержит старый код? Как всегда рекламный ответ - используйте специализированную систему статического анализа Viva64, включенную в состав PVS-Studio.



Найдите ошибки в своем C, C++, C# и Java коде

Предлагаем попробовать проверить код вашего проекта с помощью анализатора кода PVS-Studio. Одна найденная в нём ошибка скажет вам о пользе методологии статического анализа кода больше, чем десяток статей.

goto PVS-Studio;

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


Найденные ошибки

Проверено проектов
346
Собрано ошибок
13 188

А ты совершаешь ошибки в коде?

Проверь с помощью
PVS-Studio

Статический анализ
кода для C, C++, C#
и Java

goto PVS-Studio;