Setting an array of a com class triggers a read access

0

I have been trying to figure out the cause of an read access memory exception and could track down the problem a bit but didn't find its exact source. The problem seems to be triggered in the following code

HRESULT MCMyOutputPin::EnumMediaTypes(IEnumMediaTypes** types)
{
    MyMediaHandler* myhandler;
    CoInitialize(NULL);
    HRESULT hr = CoCreateInstance(CLSID_MyMediaHandler, NULL, CLSCTX_INPROC_SERVER, IID_IEnumMediaTypes, (void **) & myhandler);
    ASSERT(types[0] != NULL);
    types[0] = myhandler; //This causes the error


    return hr;

}

If i replace that line with

CBaseOutputPin::EnumMediaTypes(types);

The error is not caused, but i also don't have the desired functionality

Using the debugger and integrated disassembler i can see that the cpu reads the invalid address in the

RtlFreeHeap function.

So I guess it tries to free something that doesn't exit there any more.

For completeness here is the whole class:

#include "CMyOutPutPin.h"
#include <fstream>
#include <dvdmedia.h>
#include "MyMediaHandler.h"
MCMyOutputPin::MCMyOutputPin(MyFilter* parent, HRESULT *phr, LPCWSTR pName) : CBaseOutputPin(NAME("MyOutPutPin"), parent, &parent->m_lock_filter, phr, pName)
{
    myLogger = new MyLogger();
    this->isConnected = FALSE;




}



BOOL MCMyOutputPin::IsConnected()
{
    return this->isConnected;
}
MCMyOutputPin::~MCMyOutputPin()
{

    delete myLogger;
}
HRESULT MCMyOutputPin::Connect(IPin* pPin, const AM_MEDIA_TYPE *pmt)
{
    /*VIDEOINFOHEADER2* header2 = (VIDEOINFOHEADER2 *)CoTaskMemAlloc(112);
    RECT rSource = {
        0,
        0,
        256,
        240
    };
    RECT rcTarget = {
        0,
        0,
        256,
        240
    };
    header2->rcSource = rSource;
    header2->rcTarget = rcTarget;
    header2->dwBitRate = 0;
    header2->dwBitErrorRate = 0;
    header2->AvgTimePerFrame = 333333;
    header2->dwInterlaceFlags = NULL;
    header2->dwCopyProtectFlags = NULL;
    header2->dwPictAspectRatioX = 0x00000010;
    header2->dwPictAspectRatioY = 0x0000000f;

    this->isConnected = TRUE;
    const AM_MEDIA_TYPE constType = {
        MEDIATYPE_Video,
        MEDIASUBTYPE_NV12,
        TRUE,
        FALSE,
        92160,
        FORMAT_VIDEOINFO2,
        NULL,
        112,
        (BYTE *)header2

    };*/




    /*IEnumMediaTypes **pEnum = new IEnumMediaTypes*[10];

    HRESULT hr = this->EnumMediaTypes(pEnum);
    if (FAILED(hr)) return hr;
    AM_MEDIA_TYPE **mediapmt = NULL;
    while (hr = (*pEnum)->Next(1,   mediapmt, NULL))
    {
        if (mediapmt == NULL)
        {
            break;
        }
        hr = pPin->ReceiveConnection(this, *mediapmt);
        if (hr == S_OK)
        {
            return S_OK;
        }
    }

    return VFW_E_TYPE_NOT_ACCEPTED;*/

    return VFW_E_TYPE_NOT_ACCEPTED;
}


HRESULT MCMyOutputPin::CheckMediaType(const CMediaType *pmt)
{
    myLogger->LogDebug("On CheckMediaType", L"D:\\TEMP\\yc.log");
    return S_OK;
}

HRESULT MCMyOutputPin::SetMediaType(const CMediaType *pmt)
{

    return CBaseOutputPin::SetMediaType(pmt);
}

HRESULT MCMyOutputPin::CompleteConnect(IPin *pReceivePin)
{


    return CBaseOutputPin::CompleteConnect(pReceivePin);
}

HRESULT MCMyOutputPin::BreakConnect()
{

    return CBaseOutputPin::BreakConnect();
}

HRESULT MCMyOutputPin::GetMediaType(int i, CMediaType *pmt)
{
    if (i < 0)
    {

        myLogger->LogDebug("Invalid arg in getmediatype", L"D:\\TEMP\\yc.log");
        return E_INVALIDARG;
    }
    if (i == 0)
    {
        myLogger->LogDebug("On GetMediaType", L"D:\\TEMP\\yc.log");
        pmt->majortype = MEDIATYPE_Video;
        pmt->subtype = MEDIASUBTYPE_NV12;
        pmt->formattype = GUID_NULL;
        pmt->bFixedSizeSamples = TRUE;
        pmt->bTemporalCompression = FALSE;
        pmt->lSampleSize = 1;
        pmt->cbFormat = 0;


        return S_OK;
    }
    return VFW_S_NO_MORE_ITEMS;

}

HRESULT MCMyOutputPin::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProps)
{
    myLogger->LogDebug("On DecideBufferSIze", L"D:\\TEMP\\yc.log");
    ALLOCATOR_PROPERTIES    act;
    HRESULT                 hr;

    // by default we do something like this...
    pProps->cbAlign     = 1;
    pProps->cBuffers    = 1;
    pProps->cbBuffer    = this->CurrentMediaType().lSampleSize;
    pProps->cbPrefix    = 0;

    hr = pAlloc->SetProperties(pProps, &act);
    if (FAILED(hr)) return hr;

    // make sure the allocator is OK with it.
    if ((pProps->cBuffers > act.cBuffers)  ||
        (pProps->cbBuffer > act.cbBuffer) ||
        (pProps->cbAlign > act.cbAlign)) 
        return E_FAIL;

    return NOERROR;
}

STDMETHODIMP MCMyOutputPin::Notify(IBaseFilter *pSender, Quality q)
{
    // right now we don't do anything ...
    return NOERROR;
}

HRESULT MCMyOutputPin::Deliver(IMediaSample* sample)
{

    myLogger->LogDebug("In Outputpin Deliver", L"D:\\TEMP\\yc.log");
    HRESULT hr  = m_pInputPin->Receive(sample);
    return CBaseOutputPin::Deliver(sample);
    //Forward to filter
}

HRESULT MCMyOutputPin::AgreeMediaType(IPin * pin, const CMediaType* pmt)
{
    myLogger->LogDebug("On AgreeMediaType", L"D:\\TEMP\\yc.log");
    ASSERT(pmt != NULL);
    if (pmt->majortype == MEDIATYPE_Video || pmt->majortype == MEDIATYPE_Stream)
    {                                                                                       
        return S_OK;
    }
    myLogger->LogDebug("AgreeMediaType cuould not agree", L"D:\\TEMP\\yc.log");
    return VFW_E_NO_ACCEPTABLE_TYPES;

}




HRESULT MCMyOutputPin::EnumMediaTypes(IEnumMediaTypes** types)
{
    MyMediaHandler* myhandler;
    CoInitialize(NULL);
    HRESULT hr = CoCreateInstance(CLSID_MyMediaHandler, NULL, CLSCTX_INPROC_SERVER, IID_IEnumMediaTypes, (void **) & myhandler);
    ASSERT(types[0] != NULL);
    types[0] = myhandler;

    return hr;

}

Also here is the code for the used com component

#include "MediaHandler.h"


MediaHandler::MediaHandler(const TCHAR* name, LPUNKNOWN pUnk) :CUnknown(name, pUnk)
{
    InitMediaTypes();
}


MediaHandler::~MediaHandler()
{
}

HRESULT MediaHandler::Clone(IEnumMediaTypes **pEnum)
{

    return S_OK;
}
HRESULT MediaHandler::Next(ULONG cMediaTypes,
    AM_MEDIA_TYPE **ppMediaTypes,
    ULONG *pcFetched)
{
    for (int i = 0; i < cMediaTypes; i++)
    {

        ppMediaTypes[i] = *m_pMediaType;
        m_pMediaType++;


    }
    return S_OK;
}
HRESULT MediaHandler::Reset()
{
    return S_OK;
    *m_pMediaType = m_pMediaTypeStart;

}


HRESULT MediaHandler::Skip(
    ULONG cMediaTypes)
{
    for (int i = 0; i < cMediaTypes; i++)
    {
        m_pMediaType++;
    }
    return S_OK;
}

void MediaHandler::InitMediaTypes()
{

    m_pMediaType = new AM_MEDIA_TYPE*[10];
    AM_MEDIA_TYPE *first = new AM_MEDIA_TYPE();
    first->majortype = MEDIATYPE_Video;
    first->majortype = MEDIASUBTYPE_NV12;
    first->bFixedSizeSamples = TRUE;
    first->bTemporalCompression = FALSE;
    first->lSampleSize = 0;
    first->formattype = FORMAT_VideoInfo;
    RECT rSource = {
        0,
        0,
        256,
        240
    };
    RECT rcTarget = {
        0,
        0,
        256,
        240
    };
    BITMAPINFOHEADER bitmapinfo = {
        40,
        256,
        240,
        2,
        12,
        0x3231564e,
        92160,
        0,
        0,
        0,
        0
    };
    VIDEOINFOHEADER *header = (VIDEOINFOHEADER *)CoTaskMemAlloc(sizeof(VIDEOINFOHEADER));
    header->rcSource = rSource;
    header->rcTarget = rcTarget;
    header->dwBitErrorRate = 0;
    header->dwBitRate = 0;
    header->AvgTimePerFrame = 333333;
    first->pbFormat = (BYTE *)header;
    first->cbFormat = sizeof(header);

    m_pMediaType[0] = first;
    m_pMediaTypeStart = m_pMediaType[0];

}

STDMETHODIMP MediaHandler::NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
    if (riid == IID_IEnumMediaTypes) {
        return GetInterface((IEnumMediaTypes *)this, ppv);
    }
    return S_FALSE;

}

Why does the call to RtlFreeHeap triggers a memory acces exception? When is RtlFreeHeap called? What objects in my code could have been initialized or destroyed the wrong way?

I hope I included everything relevant and that you can understand my problem

Thanks for any answers

c++
com
directshow
asked on Stack Overflow Mar 6, 2014 by Luke • edited Mar 7, 2014 by Roman R.

1 Answer

2

Apart from pretty unexpected desire to override EnumMediaTypes this way, the following is incorrect:

HRESULT MCMyOutputPin::EnumMediaTypes(IEnumMediaTypes** types)
{

    // 1 - This has to be IEnumMediaTypes*, or rather even 
    //     QzCComPtr<IEnumMediaTypes> since you request IID_IEnumMediaTypes 
    //     in the argument below
    MyMediaHandler* myhandler;

    // 2 - This is totally incorrect: this has to be always matched by 
    //     CoUninitialize and there is no way it has to be there in first 
    //     place; simply remove and never add inside any COM method ever
    CoInitialize(NULL);


    HRESULT hr = CoCreateInstance(CLSID_MyMediaHandler, NULL, 
        CLSCTX_INPROC_SERVER, IID_IEnumMediaTypes, (void **) & myhandler);

UPD. It is typical to override CBasePin.GetMediaType method:

From the pin's list of preferred media types, this method returns the type with an index value of iPosition. [...] Override this method in your derived class.

answered on Stack Overflow Mar 6, 2014 by Roman R. • edited Mar 7, 2014 by Roman R.

User contributions licensed under CC BY-SA 3.0