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

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



Об одной проблеме при миграции кода на 64-битные системы, связанной с некорректной перегрузкой виртуальных функций мы писали в наших статьях уже давно. Например, наша статья "20 ловушек переноса Си++ - кода на 64-битную платформу" вышла в марте 2007 года (хотя ничуть не утратила актуальности). В ней было описание проблемы с виртуальными функциями. Суть проблемы заключается в следующем. С незапамятных времен в библиотеке MFC есть класс CWinApp, в котором имеется функция WinHelp:

class CWinApp {
  ...
  virtual void WinHelp(DWORD dwData, UINT nCmd);
};

Для показа собственной справки в пользовательском приложении необходимо было эту функцию перекрыть:

class CSampleApp : public CWinApp {
  ...
  virtual void WinHelp(DWORD dwData, UINT nCmd);
};

И все было прекрасно до тех пор, пока не появились 64-битные системы. Тогда разработчикам MFC пришлось поменять интерфейс функции WinHelp (и некоторых других) так:

class CWinApp {
  ...
  virtual void WinHelp(DWORD_PTR dwData, UINT nCmd);
};

В 32-битном режиме типы DWORD_PTR и DWORD совпадали, а вот в 64-битном... Естественно разработчики пользовательского приложения тоже должны были сменить тип на DWORD_PTR для корректной перегрузки, но компилятор про это не говорил, и ошибка выявлялась только на этапе тестирования, когда справочная система вела себя "загадочно". За подробностями я отсылаю читателя к упомянутой выше статье.

Вспомнить эту ошибку меня заставил тот факт, что сегодня, в конце 2009 года эта ошибка до сих пор есть в коде реальных приложений. Сомневаетесь?

Есть прекрасная библиотека компонентов BCGControlBar. Наверняка вы про нее слышали, поскольку компоненты компании BCGSoft Ltd включены в Microsoft Visual Studio 2008 Feature Pack. Так вот, если скачать ознакомительную версию этой библиотеки, установить ее и выполнить поиск слова "WinHelp" по .h-файлам... то мы увидим, что везде, где якобы перекрыта эта функция, используется параметр DWORD, вместо DWORD_PTR. А это означает, что справка в 64-битной системе в этих классах будет вести себя некорректно.

Неужели подобная ошибка может до сих пор быть в коде такой известной библиотеки? Я думаю дело в том, что клиентам компании доступны исходные коды этой библиотеки и клиенты всегда могут поправить эти коды. Кроме того, в настоящее время функция WinHelp используется очень редко. Намного чаще используется HtmlHelp. А она-то в BCGControlBar имеет правильный параметр DWORD_PTR. Однако факт остается фактом. Ошибка есть во вполне реальном коде и компилятор ее не обнаружит.

Что делать? Использовать PVS-Studio. Ведь наш анализатор с момента своего создания умеет находить такие ошибки, а справочная система содержит подробный пример (смотрите описание ошибки V301).



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

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

goto PVS-Studio;

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


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

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

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

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

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

goto PVS-Studio;