double free()??

What causes the following that isn't a double free()?

1
2
*** glibc detected *** ./a.out: double free or corruption (out): 0x080887a8 ***
======= Backtrace: =========


* code is at the bottom of my post

I allocated an array of class screen with new[] (ln: 224, inside int tmpProg::setupStates())
I then create an SDL_Surface with SDL_CreateRGBSurface() (ln: 315, inside int screen::createWindow(SData &d))

When I call delete[] (ln: 159, inside tmpProg::~tmpProg()) it causes my error. Stepping through with gdb and writing some of those fprintf lines identified that the problem was caused when calling SDL_FreeSurface() on the Surface created as mentioned above (ln: 281, inside screen::~screen()).
It happens when freeing the last screen in the array, which holds position ZERO (apparently delete[] frees backwards through the array), which is the only screen to be assigned a background IMG SDL_Surface.

Having no idea what was causing the problem I went and compiled Valgrind, hoping that it would help me find and identify my problem, however when I ran my program through Valgrind it exited without error.

as such I wrote a quick test:

1
2
3
4
5
6
7
8
9
10
#include <stdlib.h>

int main()
{
    void *ptr = malloc(1);
    free(ptr);
    free(ptr);

    return 0;
}


and discovered that when running this through valgrind it erred:

 
==9773== Invalid free() / delete / delete[]


I am lost as to what is causing my little problem. I can't see anywhere that I could have freed that surface, and printing it in gdb right before calling SDL_FreeSurface() prints information that makes me think it is still there. Perhaps someone will be able to point out what I'm doing incorrectly. Thanks in advance for any help with this reasonably sized post.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
#include <SDL/SDL.h>
#include "SDL/SDL_image.h"
#include <cstdio>
        

//global functions  
SDL_Surface* loadIMG(char *filename)
{           
    SDL_Surface* img;
    if (!(img = IMG_Load(filename)))
    {       
        char *SDLerr= IMG_GetError();
        size_t errlen = 1 + strlen(SDLerr);
        char errstr[errlen];
        snprintf(errstr, errlen, "%s\n", SDLerr);
        //free(SDLerr);
        throw errstr;
        fprintf(stderr, errstr);
        return NULL;    
    }   
    else
        return img;
}

//data type for screen data
typedef struct {
    int w;
    int h;
    int bpp; 
    int fps;
    int running;
    char *title;
} SData;
    

/*
 * class screen
 */
    
class screen
{   
    public:
        screen(); 
        ~screen();
        
        int createWindow(SData &d);
        int setBackground(SDL_Surface* bg);

        SDL_Surface* render(); //function for "rendering"  the screen to a single SDL_Surface then returning a pointer to it. 

    private:
        SDL_Surface *sCurrent;
        SDL_Surface *sbg;
};  
        
        
/*  
 * class tmpProg
 */     
class tmpProg
{   
    public: 
        tmpProg(); 
        ~tmpProg();
        
        int run();
        
    private:
        SData sdata; //for holding screen dimensions

        SDL_Surface *sScreen; // Surface for the Screen

        enum states {
            ZERO,
            ONE,
            TWO,
            THREE,
            FOUR,
            FIVE,
            SIX     };

        screen* state;
        screen* cState;
        states enumState;

        int init();     //for initiating the states
        int loadImg();
        int setupStates();

};


/*
 * main()
 */
int main(int argc, char** args)
{
    tmpProg *prog = new tmpProg();
    prog->run();
    delete prog;
    return 0;
}

tmpProg::tmpProg()
{
    sdata.w = 800;
    sdata.h = 600;
    sdata.bpp = 32;
    sdata.fps = 5;
    sdata.running = 0;
    sdata.title=strdup("tmpProg");
    sScreen = NULL;
    state = NULL;
    cState = NULL;

    /*
     * init SDL
     */
    printf("Initialising SDL\n");

    if (SDL_Init( SDL_INIT_EVERYTHING) <0)
    {
        printf("Failed to init SDL\n");
        exit(1);
    }
    else
        printf("SDL Initialised\n");

    // set the screen
    sScreen = SDL_SetVideoMode(sdata.w, sdata.h, sdata.bpp, SDL_SWSURFACE);
    if (sScreen == NULL)
    {
        printf("Failed to Set Video Mode\n");
        SDL_Quit();
        exit(1);
    }
    else
    {
        printf("\nVideo Mode Set:\n");
        printf("Width: %d\n", sScreen->w);
        printf("Height: %d\n", sScreen->h);
        printf("Bit Deapth: %d bpp\n", sdata.bpp);
        printf("FPS: %d\n", sdata.fps);
    }

    // set the window caption
    SDL_WM_SetCaption(sdata.title, NULL);

}

/*
 * ~tmpProg()
 * cleans up tmpProg
 */

tmpProg::~tmpProg()
{
    if (state)
        delete[] state; // should give double free() message in here
    state=NULL;
    cState=NULL;

    free(sdata.title);
    sdata.title=NULL;

    if (sScreen)
        SDL_FreeSurface(sScreen);
    sScreen=NULL;

    SDL_Quit();
}

/*
 * run()
 * runs the tmpPrpg
 */
int tmpProg::run()
{
    // setup the states, exit the program if something fails
    if (!(init()))
        return 0;

    enumState = ZERO;
    sdata.running = 1;

    //while(sdata.running)
        cState=&state[ZERO];

        //render the screen
        SDL_BlitSurface(cState->render(), NULL, sScreen, NULL);

        // Update the Screen
        if (SDL_Flip(sScreen)<0)
        {
            fprintf(stderr, "Failed to update the Screen. \n");
            return 0;
        }

    return 1;
}

/*
 * init()
 * runs the init functions for screens
 * returns 0 on falure
 */

int tmpProg::init()
{
    if (!(setupStates()))
        return 0;
    if (!(loadImg()))
        return 0;
    return 1;
}

/*
 * setupStates()
 * sets up screen array
 */
int tmpProg::setupStates()
{
    //Create an array of screens for gameStates
    state = new screen [SIX];

    for (int i = 0; i<=SIX; i++)
    {
        state[i].createWindow(sdata);
        printf("Game State %d's render() func returns a pointer to %p.\n", i, (state[i].render()));
    }
    return 1;
}

/*
 * loadImg()
 * loads images
 */
int tmpProg::loadImg()
{
    //if ((!(state[ZERO].setBackground(loadIMG("./background.png")))))
    //    return 0;

    //unworking code (did throw segfaults)
    
    try
    {
        state[ZERO].setBackground(loadIMG("./background.png"));
    }
    catch (char *err) // doesnt catch anything meaningful
    {
        fprintf(stderr, "%s",err);
        //free(str);
        return 0;
    }
    

    return 1;
}

/*
 * screen()
 */

screen::screen()
{
    sCurrent = NULL;
    sbg = NULL;
}

/*
 * ~screen()
 * the double free() gets called in here
 */

screen::~screen()
{
    // if sCurrent exists, print its pointer loc and free it, do the same with sbg
    if (sCurrent)
    {
        printf("Freeing memory location %p, assigned to sCurrent in ~screen().\n", sCurrent);
        SDL_FreeSurface(sCurrent); //this line causes the double free()
        sCurrent = NULL;
    }

    if (sbg)
    {
        printf("Freeing memory location %p, assigned to sbg in ~screen().\n", sbg);
        SDL_FreeSurface(sbg);
        sbg = NULL;
    }
}

/*
 * render()
 * Blit the screen in a single SDL_Surface and return a pointer to it
 * return a pointer of the screen
 */


SDL_Surface* screen::render()
{
    if (sbg)
        SDL_BlitSurface(sbg, NULL, sCurrent, NULL);
    return sCurrent;
}


/*
 * createWindow()
 * creates an SDL_Surface with the same dimensions as the screen and returns a 
 * pointer to it to assign to sCurrent.
 */
int screen::createWindow(SData &d)
{
    if ((sCurrent = SDL_CreateRGBSurface(SDL_SWSURFACE, d.w, d.h, d.bpp, 0, 0, 0, 0)))
        return  1;
    else
        return 0;
}

/*
 * setBackground()
 * sets bg
 */

int screen::setBackground(SDL_Surface* bg)
{
    if (bg)
    {
        if (sbg)
            SDL_FreeSurface(sbg);

        sbg=bg;
    }
    else
    {
        fprintf(stderr, "Dont call setBackground without a surface!\n");
        return 0;
    }

    return 1;
}
Last edited on
I've not read all of it, but should you be freeing the return from IMG_GetError? I'm not certain myself, but SDL_GetError returns a static buffer.
Last edited on
lol thanks.

That's something I added as I wrote the example program. You are correct, It also causes the same problems as it tries to free unallocated memory, but it only goes in there when there is no background.png file.

however, it's also doing it when it tries to free state[0].sCurrent.
You've gone off the end of your array in:
1
2
    state = new screen [SIX];
    for (int i = 0; i<=SIX; i++)


You don't need to check for null on delete in:
1
2
    if (state)
        delete[] state; // should give double free() message in here 

but it's not an error.
Ahh, because its an enum that translates to 6 Im creating the array one smaller than I want it. Thanks very much.

One last question, less important but still annoying.

My throw statement on line 17, annoyingly enough it doesn't segfault in this program, but it does in my other one, and I can't see a difference between those functions. In any case, with this program, it throws garble, or perhaps instead garble is caught in my catch statement on 249. Any ideas?

ps. i have commented the above code and I have realised that instead of doing all that in loadIMG to add a \n to the end of the string I could just throw IMG_GetError() and add it in my fprintf statement on line 251.
Last edited on
It's throwing a local variable. It's probably overwritten by the time you get to use it. You may want to throw a std::string.

I still think you've gone off the end of your array.
lol, yeah, I did go off the end of my array. I was confused about why I got the error when in the first element instead of the end+1.
Adding an eighth enum to the set and changing the for loop to i<LAST; fixes it.

You are also correct about the throw. Thanks for the help.
Topic archived. No new replies allowed.