【问题标题】:std::wstring causes memory access violation (0xC0000005: Access Violation)std::wstring 导致内存访问冲突(0xC0000005:访问冲突)
【发布时间】:2012-05-22 00:42:37
【问题描述】:

我们的应用程序浏览命名管道列表并查找由我们的应用程序创建的命名管道。

如果我们的命名管道不存在,我们继续创建一个。但是,最近我们的客户报告了

应用程序崩溃:

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) 异常地址:78aa1ed7 (msvcr100!memcpy+0x00000057) 异常代码:c0000005(访问冲突) 异常标志:00000000 数量参数:2 参数[0]:00000000 参数[1]:0d6b8000 尝试从地址 0d6b8000 读取 SYMBOL_STACK_INDEX:0 SYMBOL_NAME: msvcr100!memcpy+57 FOLLOWUP_NAME:机器所有者 模块名称:msvcr100 IMAGE_NAME:msvcr100.dll DEBUG_FLR_IMAGE_TIMESTAMP:4ba1dbbe FAILURE_BUCKET_ID:STRING_DEREFERENCE_c0000005_msvcr100.dll!memcpy 桶 ID: APPLICATION_FAULT_STRING_DEREFERENCE_CODE_ADDRESS_MISMATCH_INVALID_POINTER_READ_WRONG_SYMBOLS_msvcr100!memcpy +57

【问题讨论】:

  • 为什么不打电话给CreateNamedPipeFILE_FLAG_FIRST_PIPE_INSTANCE 看看管道是否存在?这样,您将创建管道或知道它存在。使用您提供的内容“调试”您的问题将很困难。整个类的错误都很难调试,在几乎没有信息的情况下远程调试更是如此。
  • TmpInfo/FileName 是如何定义的? TmpInfo-&gt;FileName 崩溃时是否有示例值?在某些情况下它是否可能不会被 null 终止?
  • @luke:把它写下来作为答案。这很可能是它。 UNICODE_STRING 不保证零终止。大多数本地调用(例如这个)也没有。

标签: visual-c++ memory activex named-pipes


【解决方案1】:

我在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 字符,因此它不会崩溃。而且效率更高!

【讨论】:

  • 您的解决方案解决了问题。但是,我看到崩溃发生在 fileName = fileName.substr(0, endStringAt);而不是 fileName = std::wstring(TmpInfo->FileName);你能解释一下为什么 substr 会导致崩溃吗?我没有看到 substr 的 NULL 终止问题
  • 我不明白为什么substr 会导致崩溃。到那时,字符应该已经从TmpInfo 复制到std::wstring。你确定这是发生崩溃的地方吗?
【解决方案2】:

TmpInfo 和 TmpInfo->FileName 是如何定义的?你有 TmpInfo->FileName 崩溃时的示例值吗?

我的猜测是在某些情况下它不会被 null 终止,导致 std::wstring 的构造函数读取到不属于它的内存中。

【讨论】:

  • TmpInfo 和 TmpInfo->FileName 是如何定义的?PFILE_NAMES_INFORMATION fileNameInfo, TmpInfo;
猜你喜欢
  • 2023-03-08
  • 2016-06-15
  • 2017-08-31
  • 2023-03-15
  • 2016-07-12
  • 1970-01-01
  • 2010-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多