2012-05-14 233 views
0

我們的應用程序瀏覽命名管道列表並查找由我們的應用程序創建的命名管道。std :: wstring導致內存訪問衝突(0xC0000005:訪問衝突)

如果我們的命名管道不存在,我們繼續創建一個。然而,最近我們的客戶有報道行

應用程序崩潰:

fileName = std::wstring(TmpInfo->FileName); 

你可以查看被附在下面WinDbg的崩潰轉儲報告。這次事故是零星的,並且在任何時候都不可重現。你能幫我找出問題嗎?在將TmpInfo->FileName轉換爲wstring時是否存在問題。請注意這個組件是一個ActiveX控件。我們的ActiveX正在崩潰其他應用程序。

以下代碼負責枚舉命名管道。

typedef struct { 
     ULONG     NextEntryOffset; 
     ULONG     FileIndex; 
     ULONG     FileNameLength; 
     WCHAR     FileName[1];  
    } FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION; 


inline void EnumerateRunningPipes(std::vector<std::wstring>& pipeNames, std::wstring stringLookup,  

            bool useStringLookup, bool 

truncatePipeDirPrefix) 
    { 
     LONG ntStatus; 
     IO_STATUS_BLOCK IoStatus;  
     BOOL bReset = TRUE;  
     PFILE_NAMES_INFORMATION fileNameInfo, TmpInfo;    

     fileNameInfo = (PFILE_NAMES_INFORMATION) new BYTE[1024]; 

     HANDLE hPipe = CreateFile("//./pipe/", 
      GENERIC_READ, 
      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 
      NULL, 
      OPEN_EXISTING, 
      0, 
      NULL); 

     if(hPipe == INVALID_HANDLE_VALUE) 
      throw CEnumeratePipeException("Could not get handle to root directory for pipes.", 
      CEnumeratePipeException::ErrorType::CREATE_FILE, GetLastError());  

     USES_CONVERSION; 

     locale loc; 
     mbstate_t state = {0}; 

     while(true) 
     { 
      memset(fileNameInfo, 0, 1024); 
      ntStatus = NtQueryDirectoryFile(hPipe, NULL, NULL, NULL, &IoStatus, fileNameInfo, 

1024, 
       FileNameInformation, FALSE, NULL, bReset); 

      if (ntStatus!=NO_ERROR) 
      { 
       if (ntStatus == STATUS_NO_MORE_FILES)      


        break;    

       std::stringstream sstream;  
       sstream << "NtQueryDirectoryFile error " << ntStatus; 

       logger->writeLog(sstream.str()); 
       throw CEnumeratePipeException(
        "NtQueryDirectoryFile could not get information about the directory or 

file.", 
        CEnumeratePipeException::ErrorType::QUERY_DIR, ntStatus); 
      } 

      TmpInfo = fileNameInfo;       

      while(true) 
      {   
       const int endStringAt = TmpInfo->FileNameLength/sizeof(WCHAR);   



       std::wstring fileName; 

       try 
       {          
        fileName = std::wstring(TmpInfo->FileName);//The access violation 

occurs at this line of code. 
        fileName = fileName.substr(0, endStringAt); 
       } 
       catch (...) 
       { 
        logger->writeLog("Caught unknown exception."); 

        if (TmpInfo->FileName == NULL) 
        { 
         logger->writeLog("TmpInfo->FileName = NULL");   


        }     
       } 

       if (useStringLookup) 
       {    
        if (fileName.find(stringLookup) != std::wstring::npos) 
        {  
         if (!truncatePipeDirPrefix) 
          fileName.insert(0, L"\\\\.\\pipe\\"); 
         pipeNames.push_back(fileName); 
        } 
       } 
       else 
       { 
        pipeNames.push_back(fileName); 
       } 

       if(TmpInfo->NextEntryOffset==0) 
        break; 

       TmpInfo = (PFILE_NAMES_INFORMATION)((DWORD)TmpInfo+TmpInfo->NextEntryOffset); 
      } 

      bReset = FALSE; 
     } 

     delete fileNameInfo; 
    } 

這裏是崩潰轉儲報告的一部分:

 
FAULTING_IP: 
msvcr100!memcpy+57 [f:\dd\vctools\crt_bld\SELF_X86\crt\src\INTEL\memcpy.asm @ 185] 
78aa1ed7 f3a5 rep movs dword ptr es:[edi],dword ptr [esi] 

EXCEPTION_RECORD: ffffffff -- (.exr 0xffffffffffffffff) 
ExceptionAddress: 78aa1ed7 (msvcr100!memcpy+0x00000057) 
ExceptionCode: c0000005 (Access violation) 
ExceptionFlags: 00000000 
NumberParameters: 2 
Parameter[0]: 00000000 
Parameter[1]: 0d6b8000 
Attempt to read from address 0d6b8000 

SYMBOL_STACK_INDEX: 0 

SYMBOL_NAME: msvcr100!memcpy+57 

FOLLOWUP_NAME: MachineOwner 

MODULE_NAME: msvcr100 

IMAGE_NAME: msvcr100.dll 

DEBUG_FLR_IMAGE_TIMESTAMP: 4ba1dbbe 

FAILURE_BUCKET_ID: STRING_DEREFERENCE_c0000005_msvcr100.dll!memcpy 

BUCKET_ID: 

APPLICATION_FAULT_STRING_DEREFERENCE_CODE_ADDRESS_MISMATCH_INVALID_POINTER_READ_WRONG_SYMBOLS_msvcr100!memcpy 

+57 

+0

爲什麼不用'FILE_FLAG_FIRST_PIPE_INSTANCE'調用'CreateNamedPipe'來查看管道是否存在?這樣你就可以創建管道或知道它存在。用您提供的內容「調試」您的問題將會很困難。整個類別的錯誤都很難調試,甚至在遠程信息很少的情況下進行調試。 – 0xC0000022L

+0

如何定義TmpInfo/FileName?當它崩潰時,你有'TmpInfo-> FileName'的示例值嗎?在某些情況下它可能不會被終止? – luke

+0

@luke:把它寫成答案。這很可能。 'UNICODE_STRING'不保證零終止。大多數本地電話如這一個都不會。 – 0xC0000022L

回答

1

如何TmpInfo和TmpInfo->文件名定義? TmpInfo-> FileName在崩潰時是否有示例值?

我的猜測是,它在某些情況下不會被終止,導致std::wstring的構造函數讀入不屬於它的內存中。

+0

如何定義TmpInfo和TmpInfo-> FileName?PFILE_NAMES_INFORMATION fileNameInfo,TmpInfo; –

2

我在FILE_NAMES_INFORMATION文檔中沒有看到任何說FileName成員爲空終止的文檔。並且FileNameLength成員的存在表明它不是空終止的。

所以它很可能是

fileName = std::wstring(TmpInfo->FileName); 

正在讀了你的TmpInfo緩衝區的末尾,直到它遇到兩個連續的空字節。如果空字節在遇到不可讀的虛擬內存區域之前未遇到,則會出現訪問衝突。

我會建議更換的這兩行代碼:這個

fileName = std::wstring(TmpInfo->FileName); 
fileName = fileName.substr(0, endStringAt); 

fileName = std::wstring(TmpInfo->FileName, TmpInfo->FileNameLength); 

該構造函數將只讀取FileNameLength字符出緩衝的,所以應該不會崩潰。而且效率更高!

+0

您的解決方案解決了問題。但是,我發現崩潰發生在fileName = fileName.substr(0,endStringAt);而不是fileName = std :: wstring(TmpInfo-> FileName);你能解釋爲什麼substr會導致崩潰嗎?我沒有看到substr –

+0

NULL終止問題我不明白爲什麼'substr'會導致崩潰。到那時,這些角色應該已經從'TmpInfo'和'std :: wstring'中複製出來了。你確定這是發生崩潰的地方嗎? –