This project has moved. For the latest updates, please go here.

Outlook triggering a breakpoint while running under Visual Studio debugger and when selecting the Address Book to view

Apr 19, 2016 at 1:03 PM
Hi,

I am looking for a solution to this :

OUTLOOK.EXE has triggered a breakpoint.

I have downloaded the Samples from this site.

I am using the Sample Address Book Provider.

I have built the code using the Outlook MAPI 2010 Headers.

I copy the SABP32.dll to c:\temp and then configure MAPISVC.INF to point to this folder/file.

Outlook will install the provider (prompting for ABDB.TXT which I select).

After this I restart Outlook, then I try to open the Sample Address Book under Other Address Books in the Address Book tool of Outlook 2013.

Outlook 2013 is running under the Visual Studio as the host process for the Sample Address Book project.

Visual Studio comes forward and says Outlook has triggered a breakpoint.

I click Continue

Then I get

Unhandled exception at 0x777CC7A9 (ntdll.dll) in OUTLOOK.EXE: 0xC0000374: A heap has been corrupted (parameters: 0x777F8890).

Then I click Continue.

The Address book dialog loads with the three entries from ABDB.TXT but instead of the data from the text file, I see a number of UNICODE type characters, Chinese and Japanese script characters I believe.

Can anybody tell me what I have done wrong?

I am using Visual Studio 2013, Outlook 2013 on Windows 10 (Standard/Home, not Professional)

I have another project which is based off the Sample Address Book provider code which I have customised which has the same breakpoint triggered, I was hoping the error was somewhere in my code, I was going to try and go through and find the error. But if it is also happening in the base/sample source code, freshly uncompressed from the downloaded Zip archive, I think I am going to need some other help.

Thanks
Apr 22, 2016 at 1:31 PM
I have found a solution which works in my project.

(I don't know if I am allowed to upload a Patch so I am just going to paste the code here.)

Open abcont.cpp
Find the function CABContainer::HrCreateCntsTable()

STDMETHODIMP CABContainer::HrCreateCntsTable(LPTABLEDATA *ppCTbl)
{
    if (!ppCTbl)
            return MAPI_E_INVALID_PARAMETER;

    HRESULT         hRes     = S_OK;
    LPTABLEDATA     pTblData = NULL;
    PCRecord        pRec     = NULL;
    LPSPropValue    pProps   = NULL;

    *ppCTbl = NULL;

    if (FAILED(hRes = CreateTable(&IID_IMAPITableData,
                                  vpfnAllocBuff,
                                  vpfnAllocMore,
                                  vpfnFreeBuff,
                                  0,
                                  TBLTYPE_DYNAMIC,
                                  PR_INSTANCE_KEY,
                                  (LPSPropTagArray)&vsptCntTbl,
                                  &pTblData)))
    {
            goto LCleanup;
    }

    assert(m_pDB);
    m_pDB->GoBegin();
    pRec = m_pDB->Read();

    // Load Rows
    while (pRec)
    {
            assert(m_pLogon);
            if (FAILED(hRes = m_pLogon->HrGetCntsTblRowProps(pRec, &pProps)))
                    goto LCleanup;

            SRow sr = {0};
            sr.cValues = NUM_CTBL_COLS;
            sr.lpProps = pProps;

            if (FAILED(hRes = pTblData->HrModifyRow(&sr)))
                    goto LCleanup;

            // Release the record copy generated by Read().
            pRec->Release();
            pRec = NULL;

            vpfnFreeBuff(pProps);


            pRec = m_pDB->Read();
    }

    *ppCTbl = pTblData;
LCleanup:
    if (FAILED(hRes))
    {
            if (pTblData)
                    pTblData->Release();
    }
    if (pRec)
            pRec->Release(); // if pRec was not released, release it.

    if (pProps)
            vpfnFreeBuff(pProps);

    return hRes;
}

I found that I was getting an Exception from Outlook after LCleanup:, the line vpfnFreeBuff(pProps);
The exception was a Heap Corruption.
pProps is being used in a While loop in this function.
vpfnFreeBuff(pProps) is being called in the loop, so it shouldn't really need to be called in the LCleanup.
When vpfnFreeBuff returns, pProps is not NULL.
That is why the function is called in the LCleanup, because if(pProps) evaluates to True.
I searched the rest of the code base and I found other uses of vpfnFreeBuff(pProps); In at least one case, the next line in the code was pProps = NULL;

So that is what I have done. I have reviewed the project and inserted pProps = NULL after any call to vpfnFreeBuff(pProps); (Use the correct variable name depending on the code block of course)

I have confirmed that I no longer get the exception on this line of code.

I don't know if this "fix" applies to any other parts of the Project ie for buffers that aren't Properties. It only seems to be show stopper where the variable is used in a loop as we see here. Otherwise it doesn't really matter if the pointer is not NULL'd I suppose.

In the CRecord class, Properties are free'd with a function FreeProps(). As far as I understand, that function does not apply in this case. (There is a note that FreeProps is dependent on how the memory was allocated.)

If anybody can see any problems with this solution I would appreciate finding out about them.

I believe in this case the problem is known as a "double free" on allocated memory.

The opposite of this is a memory leak. If I have caused a memory leak then that needs to be fixed too. For now, Outlook has stopped crashing so I will proceed.
Apr 22, 2016 at 2:40 PM
Before I changed HrCreateCntsTable I thought I found the Heap allocation issue in CTxtABDatabase::Read() :

PCRecord CTxtABDatabase::Read()
{
PCRecord pRec = NULL;

    if (!m_recList.empty() && m_iter != m_recList.end() && *m_iter != NULL)
    {
        // Constructor will increase the ref count  
        pRec = new CRecord(*m_iter);
            if (!pRec)
                    return NULL;
            pRec->AddRef();

            EnterCriticalSection(&m_cs);
            // Increment iterator
            m_iter++;
            LeaveCriticalSection(&m_cs);
    }

    return pRec;
}


When I traced the code, I found that the CRecord() constructor was calling InitMembers() which was calling AddRef(), then the calling function Read() was also calling AddRef()

This seemed to be increasing the reference count more often than it was decreased with Release(), so the object was never being deleted.

I have confirmed that this issue was not causing the Heap allocation exception. However I think this could be a memory leak.

What I did was comment out the call to AddRef() in the Read() function.

//pRec->AddRef();

I found the same issue in CTxtABDatabase::Query().

I set a breakpoint on the delete this; line in the CRecord::Release() function which now triggers because the reference count is able to drop to zero.