Explain if any memory leak associated with oleaut32!APP_DATA::AllocCachedMem and ntdll!RtlAllocateHeap in windbg stack trace which appears repeatedly

2

I am trying to identify memory leak in a process(C++ Application) I am using Windbg tool to identify the memory leak.

0:000> !heap -stat -h 02e10000 
 heap @ 02e10000
group-by: TOTSIZE max-display: 20
    size     #blocks     total     ( %) (percent of total busy bytes)
    40 95857 - 25615c0  (60.70)
    953130 1 - 953130  (15.14)
    2040 16a - 2d9a80  (4.63)
0:000> !heap -flt s 40   -> filtered by size 40, as this is consuming 60%. 

Below are the 2 most repeated call stacks I am seeing  with !heap -p -a <usrptr>, with busy.

0:000> !heap -p -a 0ad77748  
    address 0ad77748 found in
    _HEAP @ 2e10000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0ad77730 000b 0000  [00]   0ad77748    00040 - (busy)
        76f9d483 ntdll!RtlpCallInterceptRoutine+0x00000026
        76f56ad7 ntdll!RtlAllocateHeap+0x00045e87
        74a5b356 combase!CRetailMalloc_Alloc+0x00000016
        748d5174 oleaut32!APP_DATA::AllocCachedMem+0x0000005f
        748d52cb oleaut32!SysAllocStringLen+0x0000005f
        739ebe9c vbscript!rtReplace+0x0000005b
        739ebe47 vbscript!VbsReplace+0x0000013a
        739d54c7 vbscript!StaticEntryPoint::Call+0x0000002f
        739d388f vbscript!CScriptRuntime::RunNoEH+0x0000267f
        739d5dce vbscript!CScriptRuntime::Run+0x000000c3
        739d5ceb vbscript!CScriptEntryPoint::Call+0x0000010b
        739d388f vbscript!CScriptRuntime::RunNoEH+0x0000267f
        739d5dce vbscript!CScriptRuntime::Run+0x000000c3
        739d5ceb vbscript!CScriptEntryPoint::Call+0x0000010b
        739d388f vbscript!CScriptRuntime::RunNoEH+0x0000267f
        739d5dce vbscript!CScriptRuntime::Run+0x000000c3
        739d5ceb vbscript!CScriptEntryPoint::Call+0x0000010b
        739d3634 vbscript!CScriptRuntime::RunNoEH+0x000023d6
        739d5dce vbscript!CScriptRuntime::Run+0x000000c3
        739d5ceb vbscript!CScriptEntryPoint::Call+0x0000010b
        739d3634 vbscript!CScriptRuntime::RunNoEH+0x000023d6
        739d5dce vbscript!CScriptRuntime::Run+0x000000c3
        739d5ceb vbscript!CScriptEntryPoint::Call+0x0000010b
        739d3634 vbscript!CScriptRuntime::RunNoEH+0x000023d6
        739d5dce vbscript!CScriptRuntime::Run+0x000000c3
        739d5ceb vbscript!CScriptEntryPoint::Call+0x0000010b
        739d3634 vbscript!CScriptRuntime::RunNoEH+0x000023d6
        739d5dce vbscript!CScriptRuntime::Run+0x000000c3
        739d5ceb vbscript!CScriptEntryPoint::Call+0x0000010b
        739fd7cb vbscript!CSession::Execute+0x0000013d
        739f76b2 vbscript!NameTbl::InvokeEx+0x00000794
        73a22191 vbscript!LocalsNameTbl::Invoke+0x00000061

0:000> !heap -p -a 0ad76eb0  
    address 0ad76eb0 found in
    _HEAP @ 2e10000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0ad76e98 000b 0000  [00]   0ad76eb0    00040 - (busy)
          unknown!printable
        76f9d483 ntdll!RtlpCallInterceptRoutine+0x00000026
        76f56ad7 ntdll!RtlAllocateHeap+0x00045e87
        6eb6fe25 webio!WapCreateSession+0x00000025
        6eb702de webio!WapCreateSessionHandle+0x0000008d
        6eb70215 webio!WebCreateSession+0x00000025
        72870e35 winhttp!WinHttpSendRequest+0x000005d5
        8fc1245 qNQCiscoCM!NQAxlConnection::sendRequest+0x00000255
        8fc150e qNQCiscoCM!NQAxlConnection::processRequest+0x0000004e
        8fc6982 qNQCiscoCM!NQAxlCommand::execute+0x00000062
        8fb6e2c qNQCiscoCM!NQAxlUtil::getSessionHandle+0x000000ac
        8fe3227 qNQCiscoCM!NQAxlSessionMgr::createNewSessionObj+0x00000077
        8fe1236 qNQCiscoCM!AXLDispatchInterface::Invoke+0x00000396
        8fd941d qNQCiscoCM!AXLCombinedDataPoint::Collect+0x0000012d
        8fb6959 qNQCiscoCM!DataRecorder::CollectDataPoints+0x00000209
        8ff16a1 qNQCiscoCM!DCCollector::CollectNow+0x00000051
        8fe8a27 qNQCiscoCM!DCCollectorList::CollectNow+0x00000087
        8fe4ebc qNQCiscoCM!DCController::CollectNow+0x000000ac
        390031 SQLite3!sqlite3_vtab_config+0x00018d41

With the first call stack I don't have any idea to proceed further. Can someone explain, what is oleaut32!APP_DATA::AllocCachedMem, and why I am seeing this call stack multiple times.

With the second call stack, I looked NQAxlConnection::sendRequest function, which had one allocation, and proper de-allocation as well. Not sure, why I am seeing this call stack as well. Below is the code for sendRequest

DWORD
NQAxlConnection::sendRequest()
{
    USES_CONVERSION;
    
    CW2A soapMsgStrConverted(m_soapMsgStr.c_str());
    std::string axlRequest = soapMsgStrConverted.m_psz;
    if (axlRequest.length() <= 0 ) {
        throw std::runtime_error("Empty request");
    }

    unsigned char *buffer = NULL;
        
    // figure out request length and allocate a buffer
    int requestLen = (int)axlRequest.length();
    buffer = new unsigned char[requestLen + 1];

    if (buffer == NULL) {
        // memory error
        throw std::runtime_error("Out of memory");
    }
    else {
        memset(buffer, '\0', requestLen+1);
    }

    strncpy((char*)buffer, axlRequest.c_str(), requestLen);
    buffer[requestLen] = '\0';

    // Improve AXL throttling coverage and prevent erroneous events
    // implement retry looping to better handle AXL throttle errors
    int retryCount = 0;
    const static int MAXRETRYCOUNT = 2;
    bool applyAXLthrottle = false;

    do {
        try {
            // set the security options based on the SSL flag        
            this->setSecurityOptions();
                
            DWORD dwBytesWritten = (DWORD)m_HTTPHeader.length() + (DWORD)requestLen;
            // Send the request 
            if (this->isSimCallManager()) {
                this->LogPrintf(L"Sent following request to %s:%d \n %s \n %s \n",
                this->getServerAddress().c_str(),
                this->getHTTPPort(),
                this->getHTTPHeader().c_str(),  // contains base64 uid&pwd show dont log it
                this->getSoapMessage().c_str());

            }
            else {
                this->LogPrintf(L"Sent following request to %s:%d \n\n%s \n",
                                this->getServerAddress().c_str(),
                                this->getHTTPPort(),
                                //this->getHTTPHeader().c_str(),  // contains base64 uid&pwd show dont log it
                                this->getSoapMessage().c_str());
            }

            BOOL bReturn = WinHttpSendRequest(m_hRequest,                     //  HINTERNET hRequest,
                                            m_HTTPHeader.c_str(),           // LPCWSTR pwszHeaders,
                                            (DWORD)m_HTTPHeader.length(),   // DWORD dwHeadersLength,
                                            (LPVOID)buffer,                 // LPVOID lpOptional, 
                                            (DWORD)axlRequest.length(),     // DWORD dwOptionalLength,
                                            dwBytesWritten,                 // DWORD dwTotalLength,
                                            0);                             // DWORD_PTR dwContext
            if (!bReturn) {
                DWORD dwErr = GetLastError();
                this->LogPrintf(L"Send request to %s failed - last error: %d", 
                this->getServerAddress().c_str(), dwErr);

                throw dwErr;
                
            }

            // receive the response ...
            bReturn = WinHttpReceiveResponse(m_hRequest,   //  HINTERNET hRequest,
                                                NULL);   //  reserved
            if (!bReturn) {
                DWORD dwErr = GetLastError();
                this->LogPrintf(L"Receive response from %s failed - last error: %d", 
                                this->getServerAddress().c_str(), dwErr);
                throw dwErr;
                
            }
         
            // retrieve the status oode from the reponse 
            this->retrieveStatusCode();


        }
        catch (...) {
            delete [] buffer;
            buffer = NULL;
            throw;
        }

        this->LogPrintf(L"NQAxlConnection::sendRequest Response Status Code: %i", this->getStatusCode());

        applyAXLthrottle = false;

        if (this->getStatusCode() == 500) {
            DWORD statusCode = this->retrieveStatusCode();

            // we need to check fault code!
            // note - status >= 500 is returned if the request is invalid and
            // sometimes will have fault code in the response
            // so look for a fault code and also return it
            std::wstring response;
            this->getResponse(response);
            std::wstring faultCode;
            std::wstring faultString;
            std::wstring detailCode;
            if ( this->responseHasFault(response, faultCode, faultString, detailCode)) {
                this->LogPrintf(L"NQAxlConnection::sendRequest fault code of %s", faultCode.c_str());
                if (faultCode.find(L"RateControl") != std::wstring::npos) {
                    applyAXLthrottle = true;
                    this->LogPrintf(L"NQAxlConnection::sendRequest AXL throttle; waiting 60 seconds");
                    retryCount++;
                    this->LogPrintf(L"NQAxlConnection::sendRequest retryCount: %i of %i", retryCount, MAXRETRYCOUNT);
                    Sleep(61100);
                    this->LogPrintf(L"NQAxlConnection::sendRequest AXL throttle; wait complete");
                }
            }
        }
    } while (applyAXLthrottle && (retryCount < MAXRETRYCOUNT));

    // free up the buffer
    delete [] buffer;
    buffer = NULL;
    
    return this->getStatusCode();
}

Can someone explain if there is any leak with these 2 call stacks, which I need to take care.

c++
memory-leaks
asked on Stack Overflow Aug 27, 2020 by Vivek Raja

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0