代码之家  ›  专栏  ›  技术社区  ›  Odrade

来自无关库对象的静态变量损坏(反之亦然)

  •  0
  • Odrade  · 技术社区  · 16 年前

    我有一个小型的vc++应用程序,分为两部分。第一部分包含主要功能,并编译为静态库。第二部分是windows服务,它从第一部分链接到库。

    我看到一些奇怪的行为是由记忆衰退引起的。通过设置数据断点等,我能够确定每次写入两个库对象中的某个成员时,服务条中的静态变量都会被损坏。相反,当写入静态变量指向的位置时,库对象的成员会损坏。有物体重叠吗?

    编辑:我忘了在我的服务代码中提到blahhelper实例在全局范围内。这支持重叠理论,因为blahhelper和servicebase::m_服务都应该在exe的全局数据区域中。

    edit2:通过查看原始内存并检查所有相关对象的地址,我已经确认blahhelper对象与servicebase::m_服务指针重叠。为什么会这样?

    下面是感兴趣的类定义:

    // This is the basis of my service.  I derive from this and override 
    // the start() and  stop() methods to implement the service.
    class ServiceBase
    {
    public:
    
        virtual ~ServiceBase();
    
        static void Run(ServiceBase& service);
    
    protected:
    
        ServiceBase(DWORD controlsAccepted = SERVICE_ACCEPT_PAUSE_CONTINUE | 
                                             SERVICE_ACCEPT_STOP | 
                                             SERVICE_ACCEPT_SHUTDOWN);
    
        virtual void Start(DWORD control) = 0;
        virtual void Stop(DWORD control) = 0;
    
        void UpdateState(DWORD state,
                         HRESULT errorCode = S_OK);
    
        const std::wstring& ServiceName() const;
    
    private:
    
        void SetServiceStatus();
    
        static void WINAPI ServiceMain(DWORD argumentCount,
                                       PWSTR* arguments);
    
        static void WINAPI Handler(DWORD control);
    
        static ServiceBase* m_service;  // This is being corrupted
        SERVICE_STATUS_HANDLE m_handle;
        ServiceStatus m_status;
        std::wstring m_serviceName;
    
    };
    

    这是图书馆里的一个班。当我将库链接到我的service exe并实例化blahhelper对象时,我看到一些与内存损坏有关的奇怪问题。

    // Writing to _blah2Open or _blah1Open causes corruption of ServiceBase::m_status
    class BlahHelper
    {
        // Names changed to protect the innocent
    public:
        BlahHelper();
        ~BlahHelper();
    
        HRESULT GetSomeInfo();
        HRESULT GetSomeStatus(LPWORD statPosition);
    
        void Init(char blah1Sp[], char blah2Sp[], HWND messageWindow);
        bool Blah1ConnectionOpen(){return _blah2Open;};
        bool Blah2ConnectionOpen(){return _blah1Open;};
        hash_map<string,short> GetSomeJunk(){return _someJunk;};
        void Refreshblah1Config();
        bool HasItemsTakenSensor(){return _blah1HasItemsTakenSensor;};
        void Enterblah2();
        void blah2Exited();
        void Ackblah2ExitReq();
        void Cleanup();
        void Initblah1();
        void Initblah2();
    
    private:
    
        LPWFSRESULT OpenSession(char* spName, HSERVICE* handle);
        LPWFSRESULT Getblah1Caps();
        void Cleanupblah1();
        void Cleanupblah2();
        void Closeblah1();
        void Closeblah2();
        void Openblah1();
        void Openblah2();
        void Registerblah1();
        void Registerblah2();
        void Checkblah1Caps();
        void CheckSomeJunk();
        void Getblah1Config();
        void LogMessage(string message, int logLevel);
    
        char* _SpName1;
        char* _SpName2;           
        HWND _messageWindow;      
        HSERVICE _Handle1;      
        HSERVICE _Handle2;      
        bool _blah2Open;              // writing to this causes corruption of ServiceBase::m_service
        bool _blah1Open;              // writing to this causes corruption of ServiceBase::m_service
        const string _logSource;
        const int _logMsgId;
        bool _blah1HasItemsTakenSensor;
    
        hash_map<string, short> _someJunk;
    };
    

    正如我所说,一个数据断点显示,编写_blah1open或_blah2open会损坏servicebase::m_服务。作为进一步的确认,我注释掉了blahhelper实现中写入这些值的每一行代码,这些错误就消失了。

    如果我改变了blahhelper成员的声明顺序,我仍然会看到内存损坏问题,但症状会改变。

    如果我直接将库代码包含在服务中,我就不会再看到这个问题了。除了诊断目的,我不能这样做,但它确实表明在链接过程中发生了一些奇怪的事情。

    另一件需要注意的事情是,库是用多字节字符集编译的,而链接库的服务应用程序是用unicode编译的。这将很难改变。

    有谁能提出可能发生这种情况的可能原因,或诊断问题的方法?当我意识到我有内存损坏,我希望有一个简单的原因(如缓冲区溢出)。但是,我不知道为什么一个物体会像这样踩在另一个物体上。

    2 回复  |  直到 16 年前
        1
  •  1
  •   rep_movsd    16 年前

    你的意思是移动服务本身改变了还是*移动服务改变了?

    如果您检查&u blah2open和m_服务,地址是否匹配?

    (请记住_blah2open是一个变量,m_service是一个指针,所以您需要_blah2open的地址和m_service的值)

    bu blah2open的地址一定在堆或堆栈上,作为cblahhelper的一部分进行分配,因此该地址不太可能指向m_服务的内容。

    如果是移动服务改变指向的内容, 一种可能的情况是: m_服务是在代码中的某个地方初始化的,但由于某些原因,在您的情况下不会调用静态初始化器,因此m_服务会随机指向某个地方,当某个对象被分配到那里时,内容会被覆盖。 您需要在程序运行的最开始处放置一个数据断点,并跟踪每次M U服务更改的时间。

    另一方面,如果您说m_service和_blah1open在故障点有相同的地址: 两个不同的变量(不在一个联合中)总是有不同的地址,因此对于内存中共享同一地址的m_service和_blah2open没有逻辑场景。这意味着编译器生成的代码中有一个根本性的错误,这是极不可能的……

        2
  •  0
  •   Mark B    16 年前

    因为这两个片段是用不同的选项编译的,您检查了 sizeof(BlahHelper) 从每个模块的角度来看是否相同?编译选项可能导致结构布局看起来不同,从而允许内存重叠。否则我看不到blahhelper的成员有任何方法覆盖你的statc指针。