Skip to main content
GameDev.net gamedev.net
🔒 Locked

Problem with calloc

Started by badwolf Dec 1, 2008 at 9:08 PM 3 replies 1k views
Original Post
badwolf
badwolf
I have a class which represents a sprite in the game engine I am writing. For some reason, if a second instance of the class is created, once calloc is reached I receive a Segmentation Fault. I believe I am freeing the memory correctly but either way I can not fathom why this only happens to the 2nd instance of the class. If I only create one sprite object everything loads fine and is displayed correctly in my application.

char* chrXMLBuffer = (char*) calloc (intXMLFilesize, sizeof(int));
I am declaring the instances of my sprite class as so:

cGFXSprite sprLogo("ForLove_Logo_Large.SPR");
cGFXSprite sprBox("Box.SPR");
Here is my complete source code for this class: cGFXSprite.h:

#ifndef CGFXSPRITE_H_INCLUDED
#define CGFXSPRITE_H_INCLUDED

#include <SDL.h>
#include <string>
#include <vector>

using namespace std;

class cGFXSprite {
    public:

        vector<SDL_Surface*> vsurfFrames;

        string strID;

    private:

        int intFrameCount;
        int intDelay;
        bool bTransparent;
        SDL_Color rgbTransparency;
        char chrAlpha;


    public:

        cGFXSprite(string strFilename);

    private:
        void LoadSprite(string strFilename);
        void LoadXML(char* chrXMLBuffer, string strFilename);
};

#endif // CGFXSPRITE_H_INCLUDED
cGFXSprite.cpp:

#include <zlib.h>

#include "cGFXSprite.h"
#include "./MyLibs/TinyXML/tinyxml.h"

#include <fstream>

cGFXSprite::cGFXSprite(string strFilename)
{
    LoadSprite(strFilename);
}

void cGFXSprite::LoadSprite(string strFilename)
{
    //Make sure the filename reflects the actual directory structure

    strFilename = "./gfx/" + strFilename;

    //Open the sprite file for reading

    gzFile gzSprite = gzopen(strFilename.c_str(), "rb8");
    if(!gzSprite)
    {
        fprintf(stderr, "In xGFXSprite constructor: Could not open %s.", strFilename.c_str());
        gzclose(gzSprite);
        exit(69);
    }

    //Find the size of the XML file

    int intXMLFilesize;
    gzread(gzSprite, &intXMLFilesize, sizeof(int));

    //Create a buffer for the XML info

    char* chrXMLBuffer = (char*) calloc (intXMLFilesize, sizeof(int));

    //Read XML into buffer

    gzread(gzSprite, chrXMLBuffer, intXMLFilesize);

    //Load the info from the XML file into variables

    LoadXML(chrXMLBuffer, strFilename);

    //Free our XML buffer

    free (chrXMLBuffer);

    //Begin reading the bitmaps

    int intBMPFilesize;

    for(int i = 0; i < intFrameCount; i++)
    {

        gzread(gzSprite, &intBMPFilesize, sizeof(int));

        //Create a buffer for the BMP

        char* chrBMPBuffer = (char*) calloc (intBMPFilesize, sizeof(int));

        //Read BMP file into buffer

        gzread(gzSprite, chrBMPBuffer, intBMPFilesize);

        //Create SDL_RWops

        SDL_RWops* rwSprite = SDL_RWFromMem(chrBMPBuffer, intBMPFilesize);

        //Create a surf

        SDL_Surface* surfSprite = SDL_LoadBMP_RW(rwSprite, 1);

        //Put surf in the vector

        vsurfFrames.push_back(surfSprite);

        //Free our RWops

        SDL_FreeRW(rwSprite);

        //Free our buffer

        free (chrBMPBuffer);

        //Set the attributes in the XML file to the surface
        //Color Key

        if(bTransparent)
        {
            int intColorKey = SDL_MapRGB( vsurfFrames->format, rgbTransparency.r, rgbTransparency.g, rgbTransparency.b);

            if(SDL_SetColorKey(vsurfFrames, SDL_SRCCOLORKEY | SDL_RLEACCEL, intColorKey) == -1)
            {
                fprintf(stderr, "Warning: In cGFXSprite constructor: Color key will not be used, reason: %s\n", SDL_GetError());
            }
        }

        //Alpha

        SDL_SetAlpha(vsurfFrames, SDL_SRCCOLORKEY | SDL_RLEACCEL, chrAlpha);
    }

    gzclose(gzSprite);
}

void cGFXSprite::LoadXML(char* chrXMLBuffer, string strFilename)
{
    //Parse buffer with TinyXML

    TiXmlDocument* xmlSpriteDoc = new TiXmlDocument();
    xmlSpriteDoc->Parse(chrXMLBuffer);

    //Get the root node

    TiXmlElement* xmlSprite;
    xmlSprite = xmlSpriteDoc->FirstChildElement("Sprite");

    if (!xmlSprite) {
        fprintf(stderr, "Unable to read <Sprite> node in SPR file %s.", strFilename.c_str());
        xmlSpriteDoc->Clear();
        delete xmlSpriteDoc;
        exit(69);
    }

    //Get the ID node

    TiXmlElement* xmlID;
    xmlID = xmlSprite->FirstChildElement("ID");

    if (!xmlID) {
        fprintf(stderr, "Unable to read <ID> node in SPR file %s.", strFilename.c_str());
        xmlSpriteDoc->Clear();
        delete xmlSpriteDoc;
        exit(69);
    }

    //Read ID to variable

    strID = xmlID->GetText();

    //Get the FrameCount node

    TiXmlElement* xmlFrameCount;
    xmlFrameCount = xmlSprite->FirstChildElement("FrameCount");

    if (!xmlFrameCount) {
        fprintf(stderr, "Unable to read <FrameCount> node in SPR file %s.", strFilename.c_str());
        xmlSpriteDoc->Clear();
        delete xmlSpriteDoc;
        exit(69);
    }

    //Read FrameCount to variable

    intFrameCount = atoi(xmlFrameCount->GetText());

    //Get the Delay node

    TiXmlElement* xmlDelay;
    xmlDelay = xmlSprite->FirstChildElement("Delay");

    if (!xmlDelay) {
        fprintf(stderr, "Unable to read <Delay> node in SPR file %s.", strFilename.c_str());
        xmlSpriteDoc->Clear();
        delete xmlSpriteDoc;
        exit(69);
    }

    //Read Delay to variable

    intDelay = atoi(xmlDelay->GetText());

    //Get the Transparent node

    TiXmlElement* xmlTransparent;
    xmlTransparent = xmlSprite->FirstChildElement("Transparent");

    if (!xmlTransparent) {
        fprintf(stderr, "Unable to read <Transparent> node in SPR file %s.", strFilename.c_str());
        xmlSpriteDoc->Clear();
        delete xmlSpriteDoc;
        exit(69);
    }

    //Read Transparent to variable

    string strTransparent = xmlTransparent->GetText();
    if(strTransparent == "True")
    {
        bTransparent = 1;
    }
    else if(strTransparent == "False")
    {
        bTransparent = 0;
    }
    else
    {
        fprintf(stderr, "<Transparent> tag has invalid value of %s in SPR file %s.", strTransparent.c_str(), strFilename.c_str());
        xmlSpriteDoc->Clear();
        delete xmlSpriteDoc;
        exit(69);
    }

    if (bTransparent) //then get the ColorKey node
    {
        TiXmlElement* xmlColorKey;
        xmlColorKey = xmlSprite->FirstChildElement("ColorKey");

        if (!xmlTransparent)
        {
            fprintf(stderr, "Unable to read <ColorKey> node in SPR file %s.", strFilename.c_str());
            xmlSpriteDoc->Clear();
            delete xmlSpriteDoc;
            exit(69);
        }

        //Get the color attribute of the ColorKey node

        rgbTransparency.r = atoi(xmlColorKey->Attribute("Red"));
        rgbTransparency.g = atoi(xmlColorKey->Attribute("Green"));
        rgbTransparency.b = atoi(xmlColorKey->Attribute("Blue"));
    }

    //Get the Alpha node

    TiXmlElement* xmlAlpha;
    xmlAlpha = xmlSprite->FirstChildElement("Alpha");

    if (!xmlDelay) {
        fprintf(stderr, "Unable to read <Alpha> node in SPR file %s.", strFilename.c_str());
        xmlSpriteDoc->Clear();
        delete xmlSpriteDoc;
        exit(69);
    }

    //Read Alpha to variable

    int intAlpha = atoi(xmlAlpha->GetText());
    if(intAlpha < 0 || intAlpha > 255)
    {
        fprintf(stderr, "In function LoadXML of cGFXSprite, Alpha value is out of bounds in SPR file %s.", strFilename.c_str());
        xmlSpriteDoc->Clear();
        delete xmlSpriteDoc;
        exit(69);
    }

    chrAlpha = intAlpha;

    xmlSpriteDoc->Clear();
    delete xmlSpriteDoc;
}
Thanks!
iMalc
iMalc
calloc - oh but you're using C++! [cool], that's not how we do things in C++.
In C++ we use new and delete. Except we also only use them when absolutely necessary. In your case what you want is a std::vector which you resize() to intXMLFilesize, and pass the address of the first element into gzread and LoadXML.
Viola, now "IT JUST WORKS!", you don't have to mess around wondering if you got the memory management correct [cool]. In fact, at the moment you seem to be allocating four times more memory than you need (refer to the second parameter in calloc).

You should also learn to use the auto_ptr. This line:
TiXmlDocument* xmlSpriteDoc = new TiXmlDocument();
becomes
std::auto_ptr<TiXmlDocument> xmlSpriteDoc(new TiXmlDocument());
and then every single one of those ten delete lines can be removed, and what's more you'll never have to worry about missing the delete when you add more code [cool]. The destructor should be taking care of those Clear() calls as well, so you can remove the ten of those as well.
DevFred
DevFred
Why are you mixing classes and calloc? "C with classes" has been dead for 25 years. Learn C++.
Antheus
Antheus
    int intXMLFilesize;    gzread(gzSprite, &intXMLFilesize, sizeof(int));    //Create a buffer for the XML info    char* chrXMLBuffer = (char*) calloc (intXMLFilesize, sizeof(int));


You have char * array, but tell it to allocate array of ints. Not a problem as such, just 4/8 times as much memory.

But more importantly, you don't check if gzread or calloc fails. Are you sure intXMLFilesize contains proper value?

[Edited by - Antheus on December 2, 2008 8:45:42 AM]
SiCrane
SiCrane
A segfault in calloc() or really any memory allocation function is generally an indication that you've got heap corruption somewhere. Double check to make sure that you don't have any buffer overruns or similar errors in your code.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.