Произошло переполнение буфера
Несколько дней назад моя компания изменила нашу операционную систему с Windows XP на Windows 7 (32-разрядная версия) в целях безопасности.
Я использую C++ в VS 2008, QT 4.8.1 и Boost. Выравнивание членов структуры в моем приложении составляет 1 байт (/Zp1).
После изменения я обнаружил одну ошибку:
Я загружаю библиотеку, которую сделал QPluginLoader
а потом я использую qobject_cast
чтобы привести его к моему интерфейсу. В моей библиотеке я могу загрузить другую.
Когда я тестировал свое приложение в режиме отладки после изменения операционной системы, все было в порядке. Все работало так, как и предполагалось, затем я изменил его на Release, и мое приложение начало падать.
Когда я отладил его с VS 2008, я увидел эту ошибку:
В my_app.exe произошло переполнение буфера, которое повредило внутреннее состояние программы. Нажмите Break, чтобы отладить программу, или Continue, чтобы завершить программу.
Для получения дополнительной информации см. Раздел справки "Как отладить проблемы переполнения буфера".
Приложение по-прежнему отлично работает в Windows XP (режим выпуска и отладки).
Сначала я думал, что это из-за зависимости или чего-то, что я пропустил. После нескольких часов тестирования и отслеживания моего приложения с регистрацией в режиме Release я наконец-то выяснил, что не так. Мое приложение падает, когда один метод пытается вернуть значение (что-либо) другому, вызвавшему его внутри библиотеки.
Например:
Метод B возвращает Bool, и я вызываю его в методе A. Когда метод B завершен и готов вернуть значение Bool методу A, приложение перестает работать. Также происходит сбой, когда он хочет вернуться к методу, который загрузил библиотеку, если метод возвращает значение. Так или иначе, это нормально с методом, который не возвращает никакого значения (void).
Чтобы быть уверенным, что именно не так, код внутри моих методов, я сделал другое приложение (тестер) и начал добавлять свой код по частям, чтобы найти ошибку. Я считаю, что это как-то связано с QT.
Пожалуйста, проверьте следующий код и скажите мне, если вы знаете, что не так.
У меня есть main.cpp, который загружает плагин, как это:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString filename = "correct path";
QPluginLoader* pluginLoader = new QPluginLoader(filename);
QObject *plugin = pluginLoader->instance();
PluginInterface* plugin_instance;
if (plugin)
{
SecureZeroMemory(&plugin_instance, sizeof(PluginInterface));
plugin_instance = qobject_cast<PluginInterface *>(plugin);
}
bool result = plugin_instance->initialize();
return a.exec();
}
Это мой интерфейс:
class PluginInterface
{
public:
virtual bool initialize() = 0;
};
QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(PluginInterface,"some text");
QT_END_NAMESPACE
Я делаю свою библиотеку так:
plugin.hpp
class Plugin : public QObject, public PluginInterface
{
Q_OBJECT
Q_INTERFACES(PluginInterface)
public:
Plugin();
bool initialize();
};
plugin.cpp
#define SUPPORTED_VERSIONS 0x01011403
#define WFS_TRACE_NONE 0
bool Plugin::initialize()
{
WFSVERSION wfs_version;
HRESULT hRes;
cout << "WFSStartUp" << endl;
hRes = WFSStartUp(SUPPORTED_VERSIONS, &wfs_version);
WORD version = wfs_version.wVersion;
cout << "version : " << version << endl;
DWORD dwTrace = WFS_TRACE_NONE;
cout << "WFSCreateAppHandle" << endl;
HRESULT hRes2;
HANDLE app_handle;
hRes2 = WFSCreateAppHandle(&app_handle);
cout << "Result : " << hRes2 << endl;
return true;
}
Q_EXPORT_PLUGIN2(my_plugin, Plugin);
Это вывод моего приложения для тестирования:
WFSStartUp
версия: 63424
WFSCreateAppHandle
Результат: 0
Приложение Crash!!
Код внутри Plugin::initialize()
работает отлично. Я копирую / вставляю main()
и запустил приложение, чтобы убедиться в этом.
Что здесь не так? Что мне не хватает?
3 ответа
Мне пришлось изменить несколько параметров сборки Visual Studio, чтобы решить эту проблему!
- Оптимизация = Пользовательская (Свойства конфигурации -> C/C++ -> Оптимизация)
- Расширение встроенной функции = по умолчанию (Свойства конфигурации -> C/C++ -> Оптимизация)
Я уже тестировал без SecureZeroMemory, и он по-прежнему падает, SecureZeroMemery не является причиной сбоя!
Вполне возможно, что в других местах кода есть и другие подобные ошибки - места, которые вы не показываете.
По крайней мере, вы компилируете все в своем приложении (все библиотеки, библиотеки DLL и т. Д.) С помощью одного и того же компилятора и используете те же настройки? Если вы используете "/Zp1", вы должны использовать его для каждого фрагмента кода, включая сам Qt. Такие флаги компилятора делают скомпилированный ими двоичный код несовместимым с кодом, скомпилированным без них.
Кроме того, "/Zp1" является убийцей производительности. Если вы хотите упаковать структуры для выгрузки их на диск и т. Д., Вы поступите неправильно. Структура, которую вы используете, не должна быть упакована. Только когда вы копируете его на диск / с диска, у вас может быть другая структура, определенная внутри, которая упакована, и вы сначала копируете данные из неупакованной в упакованную структуру, а только затем копируете ее на диск. Вы должны упаковывать отдельные структуры, используя правильные прагмы / атрибуты, а не все!
Этот код:
PluginInterface* plugin_instance;
if (plugin)
{
SecureZeroMemory(&plugin_instance, sizeof(PluginInterface));
plugin_instance = qobject_cast<PluginInterface *>(plugin);
}
будет очень сильно вызывать сбой, если SecureZeroMemory
делает то, что его имя говорит, что делает.
Чтобы обнулить указатель, просто установите его в 0.
Но упомянуть также, что это было бы бессмысленно, когда следующее, что вы делаете, это назначаете ему, как указано выше.