gtdevel
gtdevel

Reputation: 1513

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:

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. After a few clicks (calls to getVectorAllIP), the I get the access violation error on the first call to 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.

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(). If I remove columnContent.clear() it occurs at the next line 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. 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.

Upvotes: 0

Views: 589

Answers (2)

gtdevel
gtdevel

Reputation: 1513

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.

The simple explanation is that when I click the button that sets off the XLSX reader, I modify the windows registry before that. 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

Upvotes: 0

Vlad Feinstein
Vlad Feinstein

Reputation: 11311

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. 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. 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)?

Upvotes: 1

Related Questions