2010-04-27 3 views
0

두 개의 작은 VC++ 응용 프로그램이 있습니다. 첫 번째 부분은 주요 기능을 포함하며 정적 라이브러리로 컴파일됩니다. 두 번째 부분은 조각 서비스에서 라이브러리로 연결되는 Windows 서비스입니다.관련이없는 라이브러리 객체의 정적 변수 손상 (또는 그 반대)

메모리 손상으로 인해 이상한 행동이 나타납니다. 데이터 브레이크 포인트 등을 설정함으로써 라이브러리 객체 중 하나의 특정 멤버가 2 개 작성 될 때마다 서비스 피스의 정적 변수가 손상되고 있음을 확인할 수있었습니다. 반대로 정적 var이 가리키는 위치가 기록 될 때 라이브러리 객체의 멤버가 손상됩니다. 개체가 겹칠 수 있습니까?

편집 : BlahHelper의 인스턴스가 내 서비스 코드의 전역 범위에 있다는 것을 잊어 버렸습니다. BlahHelper와 ServiceBase :: m_service는 모두 exe의 전역 데이터 영역에 있어야하기 때문에 중복 이론을 지원합니다.

EDIT2 : 원시 메모리를보고 모든 관련 개체의 주소를 확인하면 BlahHelper 개체가 ServiceBase :: m_service 포인터와 겹치는 것을 확인했습니다. 왜 이것이 사실일까요?

여기에 관심있는 클래스 정의입니다 :

// 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; 

}; 

이 라이브러리의 클래스 중 하나입니다. 라이브러리를 내 서비스 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_service를 한 것으로 밝혀졌습니다. 추가 확인으로서, 나는이 값들을 쓴 BlahHelper의 모든 구현 라인을 주석 처리했으며, 부패는 사라졌다.

BlahHelper 멤버의 선언 순서를 변경하더라도 메모리 손상 문제는 계속 발생하지만 증상은 변경됩니다.

서비스에 라이브러리 코드를 직접 포함하면 더 이상 문제가 표시되지 않습니다. 진단 목적 이외의 다른 목적으로는이 작업을 수행 할 수 없지만 링크 과정에서 이상한 점이 있음을 나타냅니다.

라이브러리를 링크하는 서비스 응용 프로그램이 유니 코드로 컴파일되는 동안 라이브러리는 Muli-Byte 문자 집합으로 컴파일된다는 점도 주목해야합니다. 이것은 변경하기가 어렵습니다.

왜 이런 일이 일어날 수있는 가능한 이유 또는 문제 진단 방법을 제안 할 수 있습니까? 메모리 손상이 있음을 깨달았을 때, 나는 버퍼 오버플로와 같은 간단한 원인을 원했다. 그러나, 나는 왜 한 물체가 다른 물체에 발을 디뎠을지 모른다.

답변

1

m_service 자체가 변경되거나 * m_service가 변경된다는 의미입니까?

& _blah2Open 및 m_service를 검사하면 주소가 일치합니까?

(_blah2Open 변수임을 기억하고 m_service는 포인터입니다, 그래서 당신은 _blah2Open의 주소와 m_service의 값을 원하는) _blah2Open의 주소, 힙에 있거나 스택 바인딩으로 할당

을 CBlahHelper의 일부로, 그 주소가 m_service의 내용을 가리키는 것은 거의 없습니다.그래서 m_service 점 어딘가에 무작위, m_service 코드 어딘가에 초기화하지만, 어떤 이유로 정적 초기화는 경우에 호출되는되지 않습니다는 내용의 경우 m_service의 변화가 가리키는 있다면

, 한 가지 가능한 시나리오는 어떤 객체가 거기에 할당되면 내용이 덮어 씌워집니다. 프로그램 실행의 맨 처음에 데이터 중단 점을 넣고 매번 m_service가 변경 될 때 추적해야합니다.

반면에 m_service 및 _blah1Open이 실패 지점에서 동일한 주소를 사용한다고 가정하면 두 개의 별개의 변수 (유니온이 아님)는 항상 고유 주소를 가지므로 m_service 및 _blah2Open에 대한 논리적 시나리오가 없습니다. 메모리에 같은 주소를 공유합니다. 이것은 컴파일러가 코드를 생성하는 데있어 기본적인 오류가 발생할 가능성이 매우 낮다는 것을 의미합니다.

+0

m_service 자체가 변경됩니다. 또한 m_service 초기화는 _blah1Open 및 _blah2Open에 영향을줍니다. 몇 가지 메모리 어드레스 및 크기는 런타임 같습니다 및 m_service : 0x0053db84 크기 : 4 및 _blah1Open : 0x0053db86 크기 : 1 및 _blah2Open : 0x0053db85 크기 : 1 및 _blah1Handle : 0x0053db83 크기 : 2 및 _blah2Handle : 0x0053db81 크기 : 2 보시다시피, _blah1Open 및 _blah2Open은 m_service의 마지막 2 바이트에 있습니다. – Odrade

0

두 옵션은 다른 옵션으로 컴파일되므로 각 모듈의 관점에서 sizeof(BlahHelper)이 동일한 지 확인 했습니까? 컴파일 옵션이 구조 레이아웃을 다르게 보이게하여 메모리 겹침을 허용 할 수 있습니다. 그렇지 않으면 BlahHelper 멤버가 statc 포인터를 오버레이 할 수 없습니다.

+0

나는 이것이 사실일지도 모른다라고 생각하기 시작하고 있었다. 나는 그것을 조사 할 것이다. – Odrade

+0

크기는 내가 알 수있는 한 두 모듈 모두에서 동일합니다. 나는 그 결정을 잘못했을 수도 있습니다. – Odrade

+0

서비스로 디버깅 한 다음 직접 실행 창에서 sizeof (XfsHelper)를 실행했습니다. .lib 파일을 .exe 파일로 변경하고, 거기서 main 함수에서 같은 작업을 수행했습니다. 그런 다음 추가 시도로 GetBlahHelperSize 메서드를 .lib에 추가하고 서비스에서 호출했습니다. 모두 같은 결과를 얻었다. – Odrade