user3043262
user3043262

Reputation: 11

C++ bad_alloc caused by new?

[Fore note: I have read the existing threads in StackOverflow. None seemed to be on my question]

I am looking into the Quake 2 MD2 format. I seem to be getting a bad allocation after new'ing a pointer-array. However, if I do some horrible pointer manipulation, everything is fine. I guess the question is, why am I getting such an exception?

The first "MD2Model::Load" works. The one I posted after it gets the exception.

Basic structures :

struct MD2Header
{
    int nIdentifier;
    int nVersion;

    int nSkinWidth;
    int nSkinHeight;
    int nFrameSize;

    int nNumSkins;
    int nNumVertices;
    int nNumUV;
    int nNumTriangles;
    int nNumCmds;
    int nNumFrames;

    int nOffsetSkins;
    int nOffsetUV;
    int nOffSetTriangles;
    int nOffsetFrames;
    int nOffsetCmds;
    int nOffsetEnd;
};

struct MD2Skin
{
    char szName[64];
};

struct MD2TexCoord
{
    short t;
    short u;
};

struct MD2Triangle
{
    short nVertex[3];
    short tu[3];
};

struct MD2Vertex
{
    float   fVertex[3];
    float   fNormal[3];
};

struct MD2Frame
{
    char szName[16];
    MD2Vertex* pVerts;
};

And now, the function that reads the .md2 file:

bool MD2Model::Load( const char* pszName )
{
    FILE* pFile = NULL;

    fopen_s( &pFile, pszName, "rb" );
    if( !pFile )
        return false;

    /* Read Header */
    fread( &m_Header, sizeof(MD2Header), 1, pFile );

    /* Allocate Pointers */
    m_pSkins = new MD2Skin[m_Header.nNumSkins];
    m_pTexCoords = new MD2TexCoord[m_Header.nNumUV];
    m_pTriangles = new MD2Triangle[m_Header.nNumTriangles];
    m_pFrames = new MD2Frame[m_Header.nNumFrames];

    /* Read Skins */
    fseek( pFile, m_Header.nOffsetSkins, SEEK_SET );
    fread( m_pSkins, sizeof(MD2Skin), m_Header.nNumSkins, pFile );

    /* Read Texture Coords */
    fseek( pFile, m_Header.nOffsetUV, SEEK_SET );
    fread( m_pTexCoords, sizeof(MD2TexCoord), m_Header.nNumUV, pFile );

    /* Read Faces */
    fseek( pFile, m_Header.nOffSetTriangles, SEEK_SET );
    fread( m_pTriangles, sizeof(MD2Triangle), m_Header.nNumTriangles, pFile );

    /* Read Animations */
    struct stMD2Vertex
    {
        unsigned char nVertex[3];
        unsigned char nLightNormalIndex;
    };
    struct stMD2Frame
    {
        float fScale[3];
        float fTranslate[3];
        char szName[16];
        stMD2Vertex verts[1];
    };

    unsigned char pBuffer[30000];
    stMD2Frame* pTmp = (stMD2Frame*) pBuffer;

    fseek( pFile, m_Header.nOffsetFrames, SEEK_SET );
    for( int i = 0; i < m_Header.nNumFrames; i++ )
    {
        fread( pTmp, 1, m_Header.nFrameSize, pFile );

        m_pFrames[i].pVerts = new MD2Vertex[m_Header.nNumVertices];
        strcpy_s( m_pFrames[i].szName, pTmp->szName );

        for( int j = 0; j < m_Header.nNumVertices; j++ )
        {
            m_pFrames[i].pVerts[j].fVertex[0] = pTmp->verts[j].nVertex[0] *
                pTmp->fScale[0] + pTmp->fTranslate[0];

            m_pFrames[i].pVerts[j].fVertex[2] = -1 * (pTmp->verts[j].nVertex[1] *
                pTmp->fScale[1] + pTmp->fTranslate[1]);

            m_pFrames[i].pVerts[j].fVertex[1] = pTmp->verts[j].nVertex[2] *
                pTmp->fScale[2] + pTmp->fTranslate[2];
        }
    }

    return true;
}

Variables dumped during debugging:

nNumSkins        1          int
nNumVertices     583        int
nNumUV           582        int
nNumTriangles    422        int
nNumFrames       1          int

(I ended up removing my D3DXVECTOR3 structures to see, so it's kinda fugly..)

Alright. So, inside the 'for' loop, is where it blows up. If I were to do it like this:

//  unsigned char pBuffer[30000];
//  stMD2Frame* pTmp = (stMD2Frame*) pBuffer;

    fseek( pFile, m_Header.nOffsetFrames, SEEK_SET );
    for( int i = 0; i < m_Header.nNumFrames; i++ )
    {
        stMD2Frame* pTmp = new stMD2Frame();
        fread( pTmp, 1, m_Header.nFrameSize, pFile );

        m_pFrames[i].pVerts = new MD2Vertex[m_Header.nNumVertices];
        strcpy_s( m_pFrames[0].szName, pTmp->szName );

I get the bad_alloc exception during allocating the "m_pFrames[i].pVerts" statement. Sometimes, I don't get it, but I do get the exception when I try to new my D3D class (I'm assuming I'll get it no matter what I new afterwards). My MEM usage is extremely low, so could it be heap corruption?

I actually had to end up doing this during creating my VertexBuffer during animations as well.

Should I end up using vectors? I know they allocate more than needed, but it seems like the (most obvious)[best] way.

Upvotes: 1

Views: 1827

Answers (1)

Peter de Rivaz
Peter de Rivaz

Reputation: 33509

I would check the line:

strcpy_s( m_pFrames[0].szName, pTmp->szName );

If the string loaded from the file is not null-terminated then this copy could end up overwriting your stack space and causing corruption.

EDIT

Looking again, I think the problem is that you define stMD2Frame as

struct stMD2Frame
{
    float fScale[3];
    float fTranslate[3];
    char szName[16];
    stMD2Vertex verts[1];
};

but this only has space for one vertex.

When you read in the frame as

fread( pTmp, 1, m_Header.nFrameSize, pFile );

you will corrupt your memory.

I suggest a check that

sizeof(stMD2Frame)>=m_Header.nFrameSize 

before reading the data.

Upvotes: 2

Related Questions