简体   繁体   English

发生缓冲区溢出

[英]A buffer overrun has occurred

A few days ago, my company changed our operation system from Windows XP to Windows 7 (32-bit) for security matters. 几天前,出于安全性考虑,我公司将操作系统从Windows XP更改为Windows 7(32位)。

I use C++ in VS 2008, QT 4.8.1, and Boost. 我在VS 2008,QT 4.8.1和Boost中使用C ++。 Struct Member Alignment in my application is 1 byte (/Zp1). 我的应用程序中的结构成员对齐是1个字节(/ Zp1)。

After the change, I found one bug: 更改后,我发现了一个错误:

I load the library I made with QPluginLoader and then I use qobject_cast to cast it to my interface. 我打开我做出的库QPluginLoader ,然后我用qobject_cast丢给我的接口。 In my library I might load another. 在我的库中,我可能会加载另一个。

When I test my application on Debug mode after the operating system changed, it was all OK. 更改操作系统后,当我在调试模式下测试我的应用程序时,一切正常。 Everything was working like it suppose to, then I changed it to Release and my application started crashing. 一切都按预期进行,然后将其更改为Release,我的应用程序开始崩溃。

When I debugged it with VS 2008, I saw this error: 当我用VS 2008调试它时,我看到了此错误:

A buffer overrun has occurred in my_app.exe which has corrupted the program's internal state. my_app.exe中发生缓冲区溢出,它损坏了程序的内部状态。 Press Break to debug the program or Continue to terminate the program. 按Break调试程序,或按Continue终止程序。

For more details please see Help topic 'How to debug Buffer Overrun Issues'. 有关更多详细信息,请参见帮助主题“如何调试缓冲区溢出问题”。

The application still work fine on Windows XP (Release and Debug mode). 该应用程序在Windows XP(发行和调试模式)上仍然可以正常运行。

At the beginning, I thought it was because of a dependency or something I missed. 一开始,我以为是因为依赖或我错过了某些东西。 After a couple of hours testing and tracing my application with logging in Release mode, I finally found out what was wrong. 经过几个小时的测试,并以发布模式登录来跟踪我的应用程序,我终于找到了问题所在。 My application crashes when one method tries to return a value (anything) to another that called it inside the library. 当一种方法试图将值(任何值)返回给在库中调用它的另一个方法时,我的应用程序崩溃。

For example: 例如:

Method B return Bool and I call it in Method A. When Method B is finished and ready to return a Bool value to Method A, wy application crashes. 方法B返回Bool,我在方法A中调用它。当方法B完成并准备将Bool值返回给方法A时,应用程序崩溃。 It also crashes when it wants to return to the method that loaded the library, if the method returns a value. 如果要返回加载库的方法(如果该方法返回值),也会崩溃。 Somehow, it's ok with a method that don't return any value (void). 不知何故,可以使用不返回任何值(无效)的方法。

To be sure what is wrong exactly, the code inside my methods, I made another application (tester) and started to add my code part-by-part to find the error. 为了确定到底出了什么问题,我在方法中的代码创建了另一个应用程序(测试器),并开始逐部分添加代码以查找错误。 I believe it has something to do with QT. 我相信这与QT有关。

Please check the following code and tell me if you know what is wrong. 请检查以下代码,并告诉我您是否知道错误所在。

I have main.cpp that loads a plugin like this: 我有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();
}

This is my interface: 这是我的界面:

class PluginInterface
{
public:

    virtual bool initialize() = 0;
};

QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(PluginInterface,"some text");
QT_END_NAMESPACE

I make my library like this: 我使我的图书馆像这样:

plugin.hpp plugin.hpp

class Plugin : public QObject, public PluginInterface
{
    Q_OBJECT
    Q_INTERFACES(PluginInterface)

public:
    Plugin();
    bool initialize();  
};

plugin.cpp 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);

This is the output of my tester application: 这是我的测试器应用程序的输出:

WFSStartUp WFSStartUp
version : 63424 版本:63424
WFSCreateAppHandle WFSCreateAppHandle
Result : 0 结果:0
Application Crash!! 应用程序崩溃!

The code inside Plugin::initialize() works fine. Plugin::initialize()的代码可以正常工作。 I copy/paste it to main() and ran the application to be sure about it. 我将其复制/粘贴到main()并运行该应用程序以确保确定。

What is wrong here? 怎么了 What am I missing? 我想念什么?

This code: 这段代码:

PluginInterface* plugin_instance;

if (plugin) 
{

    SecureZeroMemory(&plugin_instance, sizeof(PluginInterface));

    plugin_instance = qobject_cast<PluginInterface *>(plugin);

}

would be very much crash-inducing if SecureZeroMemory does what its name says it does. 如果SecureZeroMemory做到了它的名字所说的那样,将会导致很多崩溃。

To zero a pointer just set it to 0. 要使指针归零,只需将其设置为0。

But, to mention also that, that would be meaningless when the next thing you do is to assign to it, as above. 但是,还要提及的是,如上所述,当您要做的另一件事是将其分配给它时,这将毫无意义

I already tested without SecureZeroMemory and it still crash, SecureZeroMemery its not the cause of the crash! 我已经在没有SecureZeroMemory的情况下进行了测试,但是它仍然崩溃,SecureZeroMemery并不是崩溃的原因!

Quite probably there are other bugs like that in other places in the code - places that you don't show. 在代码的其他地方可能还存在其他类似的错误-您未显示的地方。

At the very least, are you compiling everything in your application (all libraries, DLLs, etc.) with the same compiler, and using same settings? 至少,您是否使用相同的编译器并使用相同的设置来编译应用程序中的所有内容 (所有库,DLL等)? If you use "/Zp1", you must use it for every piece of code, including Qt itself. 如果使用“ / Zp1”,则必须对每段代码都使用它,包括Qt本身。 Such compiler flags make the code compiled with them binary incompatible with code compiled without them. 这种编译器标志使使用它们编译的代码与不使用它们编译的代码不兼容。

Besides, "/Zp1" is a performance killer. 此外,“ / Zp1”是性能杀手。 If you want to pack structures for dumping them to disk etc., you're going about it the wrong way. 如果要打包结构以将其转储到磁盘等中,那将是错误的方法。 The structure that you use shouldn't be packed. 您使用的结构不应打包。 Only when you're copying it to/from disk should you have another structure defined internally that is packed, and you first copy the data from unpacked to packed structure, and only then dump to disk. 仅当您将其复制到磁盘或从磁盘复制时,才应在内部定义另一个打包的结构,然后首先将数据从解压缩复制到打包的结构,然后再转储到磁盘。 You're supposed to pack individual structures by using proper pragmas/attributes, not everything! 您应该使用适当的编译指示/属性而不是所有内容来打包单个结构!

I had to change few Visual Studio build options to fix this problem! 我不得不更改一些Visual Studio生成选项来解决此问题!

  • Optimization = Custom (Configuration Properties -> C/C++ -> Optimization) 优化=自定义(配置属性-> C / C ++->优化)
  • Inline Function Expansion = Default (Configuration Properties -> C/C++ -> Optimization) 内联函数扩展=默认(配置属性-> C / C ++->优化)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM