简体   繁体   English

C ++-调用std :: vector的.clear()时访问冲突

[英]C++ - Access violoation when calling .clear() of std::vector

I am implementing an XLSX spreadsheet Reader in Visual Studio C++ MFC app and am getting an access violation error when executing it multiple times: 我正在Visual Studio C ++ MFC应用程序中实现XLSX电子表格阅读器,并且多次执行时遇到访问冲突错误:

First-chance exception at 0x7720e39e in VCT.exe: 0xC0000005: Access violation reading location 0x02bdddab.
Unhandled exception at 0x7720e39e in VCT.exe: 0xC0000005: Access violation reading location 0x02bdddab.
The program '[1756] VCT.exe: Native' has exited with code -1073741819 (0xc0000005).

The weird thing is that depending on the rest of my code, this can occur after the function being called twice, three times, or more... This makes me think that it has something to do with timing, but I only have the single thread running. 奇怪的是,根据我的代码的其余部分,这可能在函数被调用两次,三次或更多次之后发生。这使我认为这与计时有关,但是我只有一个线程运行。 Another one of my (more realistic) hypotheses is that it is an undefined behavior. 我的另一个假设(更现实)是它是未定义的行为。 This makes it especially difficult to debug. 这使得调试特别困难。 What confuses me is why this access violation would happen after multiple calls to the function. 让我感到困惑的是,为什么在多次调用该函数后会发生这种访问冲突。

Added to question: 添加到问题:

I call the function getVectorAllIP every time a button is clicked. 每次单击按钮时,我都会调用函数getVectorAllIP After a few clicks (calls to getVectorAllIP ), the I get the access violation error on the first call to mm_XLSXReader.xlsxGetCellOffset . 几次单击(调用getVectorAllIP )后,第一次调用mm_XLSXReader.xlsxGetCellOffset ,我收到访问冲突错误。

vector<CString> CVCTDlg::getVectorAllIP(string ipName){

    CString CSIP1;

    vector<CString> VCSIPAddresses;

    XLSXReader mm_XLSXReader;
    mm_XLSXReader.reloadFile();
    mm_XLSXReader.setFilePath(XLSX_FILE_PATH);

    for(int i = 0; i < m_vectorStrHostname.size(); i++)
    {
        CSIP1="";
        for(int iOffset = 0; iOffset < 4; iOffset++)
        {

            CSIP1.Append(mm_XLSXReader.xlsxGetCellOffset(ipName, i, iOffset).c_str());
            if(iOffset != 3)
            {
                CSIP1.Append(".");
            }
        }

        if(CSIP1 != "...")
        {

            VCSIPAddresses.push_back(CSIP1);

        }else{
            VCSIPAddresses.push_back("");
        }

    }

    return VCSIPAddresses;

}

Within xlsxGetCellOffset , the access violation error occurs within readSheetXml . xlsxGetCellOffset内发生访问冲突错误readSheetXml

string XLSXReader::xlsxGetCellOffset(string columnName, int id, int offset)
{
    string contentToReturn;
    id++;

    if(!m_bFileInMemory)
    {
        if(openm_XLSXReader())
        {
            readSharedStringsXml();
            readSheetXml();

            closem_XLSXReaders();

            m_bFileInMemory = true;
        }
    }

    for(int i = 0; i < m_header.size(); i++)
    {
        if(m_header.at(i) == columnName && m_header.size() > i + offset)
        {
            if(m_sheetContent.size() > id)
            {
                if(m_sheetContent.at(id).size() > i)
                {
                    contentToReturn = m_sheetContent.at(id).at(i+offset);
                }
            }
        }
    }

    return contentToReturn;
}

The access violation occurs during the clearing sequence at the end. 访问冲突在最后的清除序列期间发生。 Specifically at the columnContent.clear() . 特别是在columnContent.clear() If I remove columnContent.clear() it occurs at the next line tParameterColumn.clear() . 如果删除columnContent.clear()它将出现在下一行tParameterColumn.clear()

void XLSXReader::readSheetXml()
{
    if(m_m_XLSXReader)
    {
        int error = unzLocateFile(m_m_XLSXReader, SHEET_NAME, 0);
        if(error == UNZ_OK)
        {
            error = unzOpenCurrentFile(m_m_XLSXReader);
            if(error == UNZ_OK)
            {
                int readingStatus = 0;
                char readBuffer[BUFFERSIZE];
                string file;
                int indexValue;
                //Reading File
                do
                {
                    readingStatus = unzReadCurrentFile(m_m_XLSXReader, readBuffer, BUFFERSIZE);
                    file.append(readBuffer, readingStatus);
                }while(readingStatus > 0);


                //Sort Data
                vector<string> rowContent;
                rowContent = findXmlTagsContent(file, "row");

                unsigned int iHdrSize;
                m_header.clear();

                vector<string> columnContent;
                vector<string> tParameterColumn;
                vector<string> rParameterColumn;
                vector<string> tmpRow;
                for(int i = 0 ; i < rowContent.size(); i++)
                {

                    columnContent=findXmlTagsContent( rowContent.at(i), "c"); 
                    rParameterColumn=findXmlParameterInTag(rowContent.at(i), "c", "r");
                    tParameterColumn=findXmlParameterInTag(rowContent.at(i), "c", "t");
                    if(i==0){
                        iHdrSize = columnContent.size();
                    }

                    //Should be equal
                    if(columnContent.size() == tParameterColumn.size())
                    {
                        unsigned int iFilledColumns = 0;
                        for(int j = 0 ; j < columnContent.size(); j++)
                        {               

                            int columnNumber = 0;

                            if(!rParameterColumn.at(j).empty())
                            {
                                columnNumber = columnLetter2Int(rParameterColumn.at(j));
                            }

                            vector<string> value;
                            value = findXmlTagsContent(columnContent.at(j), "v");

                            if(value.size()>1){
                                value.clear();
                                value.push_back("");
                            }

                            //Header Reading
                            if( i == 0)
                            {
                                //Fill empty spaces in excel sheet with ""
                                for(int a = 1; a < columnNumber-iFilledColumns; a++)
                                {
                                    m_header.push_back("");
                                }
                                iFilledColumns=m_header.size();

                                //link to sharedString
                                if(tParameterColumn.at(j) == "s")
                                {
                                    indexValue = atoi(value.at(0).c_str());
                                    string tmpStr = m_sharedString.at(indexValue);
                                    m_header.push_back(tmpStr);
                                }
                                //Value
                                else
                                {   
                                    m_header.push_back(value.at(0));
                                }
                            }
                            // Content Reading
                            else
                            {
                                ////Fill empty spaces in excel sheet with ""
                                for(int a = 1; a < columnNumber-iFilledColumns; a++)
                                {
                                    tmpRow.push_back("");
                                }
                                iFilledColumns=tmpRow.size();
                                //link to sharedString

                                if(tParameterColumn.at(j) == "s")
                                {
                                    indexValue = atoi(value.at(0).c_str());
                                    tmpRow.push_back(m_sharedString.at(indexValue));
                                }
                                //Value
                                else
                                {
                                    if(value.size() != 0)
                                    {
                                        tmpRow.push_back(value.at(value.size()-1));
                                    }
                                    else
                                    {
                                        tmpRow.push_back("");
                                    }
                                }

                            }
                            iFilledColumns++;
                        }
                        for(int k=0;k<iHdrSize-iFilledColumns;k++){
                            tmpRow.push_back("");
                        }
                        m_sheetContent.push_back(tmpRow);
                        tmpRow.clear();
                        columnContent.clear();
                        tParameterColumn.clear();
                        rParameterColumn.clear();

                    }
                }       
            }
        }
    }
}

And just FYI, the m_m_XLSXReader is instantiated on a call to openm_XLSXReader called within xlsxGetCellOffset . 而仅供参考, m_m_XLSXReader被实例化到一个呼叫openm_XLSXReader称为内xlsxGetCellOffset Here it is for your reference: 这里供您参考:

bool XLSXReader::openm_XLSXReader()
{
    //Uncompress .xlsx
    m_m_XLSXReader = unzOpen(m_strXLSXPath.c_str());

    if(m_m_XLSXReader){
        return true;
    }
    return false;
}

Hope someone can point out some glaring obvious mistake, because I am starting to question my sanity :) Thanks. 希望有人指出一些明显的错误,因为我开始质疑我的理智:)谢谢。

This loop: 这个循环:

do
{
    readingStatus = unzReadCurrentFile(m_m_XLSXReader, readBuffer, BUFFERSIZE);
    file.append(readBuffer, readingStatus);
} while (readingStatus > 0);

will append the last read block twice, most likely producing invalid XML. 将最后一次读取的块追加两次,很可能产生无效的XML。 I don't know which library you use to read XML (can't find any references to findXmlTagsContent other than this question), and how resilient it is, but suspect it may not behave well being fed garbage. 我不知道您用来读取XML的库(除了这个问题之外,找不到任何对findXmlTagsContent引用),以及它的弹性如何,但是我怀疑它在喂入垃圾时可能表现不佳。 Plus, you are not checking for any possible errors... 另外,您不检查任何可能的错误...

Bottom line is: try reading your file like this: 底线是:尝试像这样读取文件:

while ((readingStatus = unzReadCurrentFile(m_m_XLSXReader, readBuffer, BUFFERSIZE)) > 0)
    file.append(readBuffer, readingStatus);

Also, what are you going to do if the return is negative (an error code)? 另外,如果返回值为负(错误代码),您将怎么办?

OK, So thank you all for your help and suggestions. 好的,谢谢大家的帮助和建议。

Vlad, your suggestions really got me thinking in a more logical way and then I found the problem which was completely unrelated to the actual XLSX reading. 弗拉德(Vlad),您的建议确实让我以更合乎逻辑的方式思考,然后我发现了与实际XLSX读数完全无关的问题。

The simple explanation is that when I click the button that sets off the XLSX reader, I modify the windows registry before that. 简单的解释是,当我单击启动XLSX阅读器的按钮时,我在此之前修改了Windows注册表。 In the process of recursively removing some registry keys, some sort of memory corruption occurs, that was only reflected when I got the access violation. 在递归删除某些注册表项的过程中,会发生某种形式的内存损坏,只有当我遇到访问冲突时才会反映出来。 I fixed my registry code, and now the issue is has been resolved. 我修复了我的注册表代码,现在问题已解决。

If anyone is interested about the actual issue regarding recursively deleting registry keys, keep reading... 如果有人对递归删除注册表项的实际问题感兴趣,请继续阅读...

I was using the code to recursively delete a registry key and its subkeys: 我使用代码递归删除注册表项及其子项:

Deleting a Key with Subkeys 删除带有子键的键

#include <windows.h>
#include <stdio.h>
#include <strsafe.h>

//*************************************************************
//
//  RegDelnodeRecurse()
//
//  Purpose:    Deletes a registry key and all its subkeys / values.
//
//  Parameters: hKeyRoot    -   Root key
//              lpSubKey    -   SubKey to delete
//
//  Return:     TRUE if successful.
//              FALSE if an error occurs.
//
//*************************************************************

BOOL RegDelnodeRecurse (HKEY hKeyRoot, LPTSTR lpSubKey)
{
    LPTSTR lpEnd;
    LONG lResult;
    DWORD dwSize;
    TCHAR szName[MAX_PATH];
    HKEY hKey;
    FILETIME ftWrite;

    // First, see if we can delete the key without having
    // to recurse.

    lResult = RegDeleteKey(hKeyRoot, lpSubKey);

    if (lResult == ERROR_SUCCESS) 
        return TRUE;

    lResult = RegOpenKeyEx (hKeyRoot, lpSubKey, 0, KEY_READ, &hKey);

    if (lResult != ERROR_SUCCESS) 
    {
        if (lResult == ERROR_FILE_NOT_FOUND) {
            printf("Key not found.\n");
            return TRUE;
        } 
        else {
            printf("Error opening key.\n");
            return FALSE;
        }
    }

    // Check for an ending slash and add one if it is missing.

    lpEnd = lpSubKey + lstrlen(lpSubKey);

    if (*(lpEnd - 1) != TEXT('\\')) 
    {
        *lpEnd =  TEXT('\\');
        lpEnd++;
        *lpEnd =  TEXT('\0');
    }

    // Enumerate the keys

    dwSize = MAX_PATH;
    lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL,
                           NULL, NULL, &ftWrite);

    if (lResult == ERROR_SUCCESS) 
    {
        do {

            StringCchCopy (lpEnd, MAX_PATH*2, szName);

            if (!RegDelnodeRecurse(hKeyRoot, lpSubKey)) {
                break;
            }

            dwSize = MAX_PATH;

            lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL,
                                   NULL, NULL, &ftWrite);

        } while (lResult == ERROR_SUCCESS);
    }

    lpEnd--;
    *lpEnd = TEXT('\0');

    RegCloseKey (hKey);

    // Try again to delete the key.

    lResult = RegDeleteKey(hKeyRoot, lpSubKey);

    if (lResult == ERROR_SUCCESS) 
        return TRUE;

    return FALSE;
}

//*************************************************************
//
//  RegDelnode()
//
//  Purpose:    Deletes a registry key and all its subkeys / values.
//
//  Parameters: hKeyRoot    -   Root key
//              lpSubKey    -   SubKey to delete
//
//  Return:     TRUE if successful.
//              FALSE if an error occurs.
//
//*************************************************************

BOOL RegDelnode (HKEY hKeyRoot, LPTSTR lpSubKey)
{
    TCHAR szDelKey[MAX_PATH*2];

    StringCchCopy (szDelKey, MAX_PATH*2, lpSubKey);
    return RegDelnodeRecurse(hKeyRoot, szDelKey);

}

void __cdecl main()
{
   BOOL bSuccess;

   bSuccess = RegDelnode(HKEY_CURRENT_USER, TEXT("Software\\TestDir"));

   if(bSuccess)
      printf("Success!\n");
   else printf("Failure.\n");
}

If I had values in the key I was trying to delete, then everything worked as expected. 如果我尝试删除的键中包含值,那么一切都会按预期进行。 In the case where I had a key with a subkey inside of it, they were deleted, but I began have the issues of my question above. 如果我有一个带有子键的键,它们将被删除,但是我开始遇到上述问题。

So for example this was deleted without causing me a life of pain, 因此,例如删除了该文件却没有给我带来痛苦,

[KeyName1]
--> SOME_DWORD
--> SOME_STRING

And this one caused me much pain indeed, 这确实使我很痛苦,

[KeyName2]
--> SOME_DWORD
--> SOME_STRING
--> [SubKeyName]
-----> SOME_DWORD
-----> SOME_STRING

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

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