Search code examples
clinuxsdlfractals

Pb with a C programm : double free or corruption (!prev)


A few years ago, when Benoit Mandelbrot died, I decided to make a small program to calculate and see his famous fractal set. I did it many years ago before (with turbo pascal language) - At this period, the calculus took one night. So I decided to learn a little of C language. With code::blocks and the SDL Library (and many helps), I finally wrote a program were I could see the set, and zoom inside with my mouse. It worked good, I was under windows. Instead of one night of calculus, it took 5 seconds to do the same job.

Recently I decided to discover linux, installed the same IDE with the SDL,. The program is compiling OK. It begins to run, and suddenly, when I use the mouse (left-clic up and down to select the new squared area where to zoom in), the program stops.

The message is :

double free or corruption (!prev)

The strange thing is that it never happened when I ran the code under windows. So here is a mysterious thing for me. I don't know what means double free or corruption here.

For a better help you could eventually send me, I join the code of the program (not perfect). Maybe someone could find where the problem is ... The program was writen to be seen on a 1680x1050 pxl screen.

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <SDL/SDL.h>
//#include <SDL/SDL_ttf.h>

#define MAXITERATIONS 2000
#define CONST_DIVERGENCE 4

#define LONGUEUR_ECRAN 1680 //ajout d'une zone d'information et d'interaction de 630 pixels de large à droite de l'image.
#define LARGEUR_ECRAN 1050  // côté du carré où l'image est calculée.


int i  , j ; /* i variable écran qui parcourt les abscisses entre 0 et LARGEUR_ECRAN
                j les ordonnées entre 0 et LARGEUR_ECRAN */
int n ,t ; // itérations pour le calcul de convergence
int color,color1,color2,color3 ; //variable pour la couleur

int continuer = 1;
int recalculer = 1;
int recommencer = 1;

double XDEBUT = -2.05; // coordonnées du point de départ en haut à gauche du carré du plan complexe
double YDEBUT = -1.35;
double DELTA = 2.7 ; // longueur du côté du carré du plan complexe au départ
double xC =0 , yC = 0 ; // coordonnées du point du plan où on effectue les calculs
double xZ  , yZ ; // coordonnées pour le calcul de la convergence
double xT = 0 ; // valeur temporaire d'allocation

double xTemp1 =0, yTemp1 = 0 ;
double xTemp2 =0, yTemp2 = 0 ;

int xTemoinDebut =1065; //variables pour positionner les cadres dans le Mandel témoin
int yTemoinDebut =15;   //
int deltaTemoin =600;   //

int x_1 , y_1;          //variables pour positionner le cadre de zoom dans le grand Mandel
int x_2 , y_2;          //
int xdebut , ydebut ;   //
int delta;              //

void placerPoint(SDL_Surface *surface, int x, int y, Uint32 pixel);
void petitMandel ();

int main(int argc, char *argv[])
{
    while (recommencer == 1)
    {
        recommencer = 0;
        recalculer =1;
        continuer =1;
        double XDEBUT = -2.05; // coordonnées du point de départ en haut à gauche du carré du plan complexe
        double YDEBUT = -1.35;
        double DELTA = 2.7 ; // longueur du côté du carré du plan complexe au départ

        int xTemoinDebut =1065; //variables pour positionner les cadres dans le Mandel témoin
        int yTemoinDebut =15;   //
        int deltaTemoin =600;   //

        double xC =0 , yC = 0 ; // coordonnées du point du plan où on effectue les calculs
        double xZ  , yZ ; // coordonnées pour le calcul de la convergence
        double xT = 0 ; // valeur temporaire d'allocation
        double xTemp1 =0, yTemp1 = 0 ;
        double xTemp2 =0, yTemp2 = 0 ;
        double tableauX [LARGEUR_ECRAN]= {0};   //tableau pour enregistrer les coordonnées réelles où on calcule
        double tableauY [LARGEUR_ECRAN] = {0};  //


        SDL_Init(SDL_INIT_VIDEO);
        SDL_Surface *ecran = NULL,*rectangle=NULL/*,*texte = NULL*/;
        // SDL_Event event;
        SDL_Rect position;
        ecran = SDL_SetVideoMode(LONGUEUR_ECRAN,LARGEUR_ECRAN, 32, SDL_HWSURFACE | SDL_FULLSCREEN); // mode vidéo : écran complet
        SDL_LockSurface(ecran);
        //   SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0, 0, 0)); // remplissage de l'écran en noir
        //  TTF_Font *police = NULL;
        //  SDL_Color couleurBleue = {0,0,255};
        //  TTF_Init();

        // test d'erreur d'initialisation
        /*   if (TTF_Init () == -1)
               {
                   fprintf(stderr, "Erreur d'initialisation de TTF_Init : %s \n",TTF_GetError ());
                   exit (EXIT_FAILURE);
               }*/

        /* TTF_Font *police = NULL;
         SDL_Color couleurBleue = {0,0,255};
         police = TTF_OpenFont("ankecall.ttf",20);                                                                                                                                    police = TTF_OpenFont ("angelina.ttf",65);
         texte  = TTF_RenderText_Blended (police, "Voyage chez Mandelbrot ", couleurBleue);
         while (continuer)
             {
                 SDL_WaitEvent(&event);
                     switch(event.type)
                     {
                         case SDL_QUIT:
                             continuer = 0;
                         break;
                     }

             position.x = 1060;
             position.y = 630;
             SDL_BlitSurface (texte, NULL, ecran, &position);
             SDL_Flip(ecran);
             }
         SDL_FreeSurface(texte);
         TTF_CloseFont(police);
         TTF_Quit ();
        */

        petitMandel(); //commande pour calculer un petit mandel témoin et un trait rouge

        while (recalculer == 1)
        {
            for ( j = 0 ; j < LARGEUR_ECRAN ; j ++) // balayage vertical
            {
                yC = YDEBUT + (DELTA * j)/LARGEUR_ECRAN;
                tableauY[j] = yC;
            }
            for ( i = 0 ; i < LARGEUR_ECRAN ; i ++) // balayage horizontal
            {
                xC = XDEBUT + (DELTA * i)/LARGEUR_ECRAN;
                tableauX [i] = xC;
            }

            for ( j = 0 ; j < LARGEUR_ECRAN ; j ++) // balayage vertical
            {
                yC = YDEBUT + (DELTA * j)/LARGEUR_ECRAN;
                for ( i = 0 ; i < LARGEUR_ECRAN ; i ++) // balayage horizontal
                {
                    xC = XDEBUT + (DELTA * i)/LARGEUR_ECRAN;
                    n = 0 ; // initialisation du compteur de calcul
                    xZ = 0 ;
                    yZ = 0 ;
                    xT = 0 ;
                    while ( xZ*xZ + yZ*yZ < CONST_DIVERGENCE && n < MAXITERATIONS)  /* boucle de calcul
                elle s'arretera si xZ²+yZ² >= 4 ou si on a atteint le maximum d'itérations*/
                    {
                        xT = xZ ;// variable temporaire pour le calcul de yZ
                        xZ = xZ*xZ - yZ*yZ + xC ;
                        yZ = 2*yZ*xT + yC ;
                        n ++;
                    }

                    if (n< MAXITERATIONS)                                         // On est en dehors de l'ensemble : mettre en gris
                        placerPoint(ecran,i,j,SDL_MapRGB(ecran->format,n,n,n));
                    else                                                          // On est dans l'ensemble : mettre en noir.
                        placerPoint(ecran,i,j,SDL_MapRGB(ecran->format,0,0,0));
                }
            }
            SDL_UnlockSurface(ecran);
            SDL_Flip(ecran);

            recalculer = 0;

            //Gestion des choix:
            SDL_Event event;
            while (continuer & (recalculer == 0))
            {
                SDL_WaitEvent(&event);
                switch(event.type)
                {
                case SDL_QUIT:
                    continuer = 0;
                    break;

                case SDL_MOUSEBUTTONDOWN:
                    if (event.button.button == SDL_BUTTON_LEFT)  //si clic gauche enfoncé
                    {
                        position.x = event.button.x;
                        position.y = event.button.y;
                        xTemp1 = tableauX [position.x];
                        yTemp1 = tableauY [position.y];
                        x_1 = position.x;
                        y_1 = position.y;
                    }
                    break;

                case SDL_MOUSEBUTTONUP:
                    if (event.button.button == SDL_BUTTON_LEFT)  //si clic gauche relaché
                    {
                        position.x = event.button.x;
                        position.y = event.button.y;
                        xTemp2 = tableauX [position.x];
                        yTemp2 = tableauY [position.y];
                        x_2 = position.x;
                        y_2 = position.y;

                        if (xTemp1 <xTemp2)
                        {
                            XDEBUT = xTemp1;
                            xdebut = x_1;
                        }
                        else
                        {
                            XDEBUT = xTemp2;
                            xdebut = x_2;
                        }
                        if (yTemp1<yTemp2)
                        {
                            YDEBUT = yTemp1;
                            ydebut = y_1;
                        }
                        else
                        {
                            YDEBUT = yTemp2;
                            ydebut = y_2;
                        }
                        if (fabs(xTemp1-xTemp2)<fabs(yTemp1-yTemp2))
                        {
                            DELTA = fabs(yTemp1-yTemp2);
                            delta = fabs(y_1-y_2);
                        }
                        else
                        {
                            DELTA = fabs(xTemp1-xTemp2);
                            delta = fabs(x_1-x_2);
                        }
                        // dessin du cadre blanc pour zoomer dans l'image principale
                        rectangle = SDL_CreateRGBSurface(SDL_HWSURFACE, 1, delta, 32, 0, 0, 0, 0); // Allocation du point
                        position.x = xdebut ; //  Coordonnées du point à placer
                        position.y = ydebut ;
                        SDL_FillRect(rectangle, NULL, SDL_MapRGB(ecran->format, 255,255,255)); // Remplissage du point en gris.
                        SDL_BlitSurface(rectangle, NULL, ecran, &position); // Collage du point sur l'écran
                        SDL_Flip(ecran);
                        SDL_FreeSurface(rectangle);

                        rectangle = SDL_CreateRGBSurface(SDL_HWSURFACE,delta, 1, 32, 0, 0, 0, 0); // Allocation du point
                        position.x = xdebut ; //  Coordonnées du point à placer
                        position.y = ydebut ;
                        SDL_FillRect(rectangle, NULL, SDL_MapRGB(ecran->format, 255,255,255)); // Remplissage du point en gris.
                        SDL_BlitSurface(rectangle, NULL, ecran, &position); // Collage du point sur l'écran
                        SDL_Flip(ecran);
                        SDL_FreeSurface(rectangle);

                        rectangle = SDL_CreateRGBSurface(SDL_HWSURFACE, 1, delta, 32, 0, 0, 0, 0); // Allocation du point
                        position.x = xdebut + delta; //  Coordonnées du point à placer
                        position.y = ydebut ;
                        SDL_FillRect(rectangle, NULL, SDL_MapRGB(ecran->format, 255,255,255)); // Remplissage du point en gris.
                        SDL_BlitSurface(rectangle, NULL, ecran, &position); // Collage du point sur l'écran
                        SDL_Flip(ecran);
                        SDL_FreeSurface(rectangle);

                        rectangle = SDL_CreateRGBSurface(SDL_HWSURFACE, delta, 1, 32, 0, 0, 0, 0); // Allocation du point
                        position.x = xdebut ; //  Coordonnées du point à placer
                        position.y = ydebut + delta;
                        SDL_FillRect(rectangle, NULL, SDL_MapRGB(ecran->format, 255,255,255)); // Remplissage du point en gris.
                        SDL_BlitSurface(rectangle, NULL, ecran, &position); // Collage du point sur l'écran
                        SDL_Flip(ecran);
                        SDL_FreeSurface(rectangle);

                        //dessin du cadre dans le mandelbrot témoin

                        xTemoinDebut = floor(xdebut*deltaTemoin/1050) + xTemoinDebut;
                        yTemoinDebut = floor(ydebut*deltaTemoin/1050) + yTemoinDebut;
                        deltaTemoin = floor(delta*deltaTemoin/1050);

                        rectangle = SDL_CreateRGBSurface(SDL_HWSURFACE, 1, deltaTemoin, 32, 0, 0, 0, 0); // Allocation du point
                        position.x = xTemoinDebut ; //  Coordonnées du point à placer
                        position.y = yTemoinDebut ;
                        SDL_FillRect(rectangle, NULL, SDL_MapRGB(ecran->format, 255,255,255)); // Remplissage du point en gris.
                        SDL_BlitSurface(rectangle, NULL, ecran, &position); // Collage du point sur l'écran
                        SDL_Flip(ecran);
                        SDL_FreeSurface(rectangle);

                        rectangle = SDL_CreateRGBSurface(SDL_HWSURFACE, deltaTemoin, 1, 32, 0, 0, 0, 0); // Allocation du point
                        position.x = xTemoinDebut ; //  Coordonnées du point à placer
                        position.y = yTemoinDebut ;
                        SDL_FillRect(rectangle, NULL, SDL_MapRGB(ecran->format, 255,255,255)); // Remplissage du point en gris.
                        SDL_BlitSurface(rectangle, NULL, ecran, &position); // Collage du point sur l'écran
                        SDL_Flip(ecran);
                        SDL_FreeSurface(rectangle);

                        rectangle = SDL_CreateRGBSurface(SDL_HWSURFACE, 1, deltaTemoin, 32, 0, 0, 0, 0); // Allocation du point
                        position.x = xTemoinDebut + deltaTemoin; //  Coordonnées du point à placer
                        position.y = yTemoinDebut ;
                        SDL_FillRect(rectangle, NULL, SDL_MapRGB(ecran->format, 255,255,255)); // Remplissage du point en gris.
                        SDL_BlitSurface(rectangle, NULL, ecran, &position); // Collage du point sur l'écran
                        SDL_Flip(ecran);
                        SDL_FreeSurface(rectangle);

                        rectangle = SDL_CreateRGBSurface(SDL_HWSURFACE, deltaTemoin, 1, 32, 0, 0, 0, 0); // Allocation du point
                        position.x = xTemoinDebut ; //  Coordonnées du point à placer
                        position.y = yTemoinDebut + deltaTemoin;
                        SDL_FillRect(rectangle, NULL, SDL_MapRGB(ecran->format, 255,255,255)); // Remplissage du point en gris.
                        SDL_BlitSurface(rectangle, NULL, ecran, &position); // Collage du point sur l'écran
                        SDL_Flip(ecran);
                        SDL_FreeSurface(rectangle);

                        recalculer = 1;
                    }
                    break;

                case SDL_KEYDOWN:
                    if (event.key.keysym.sym == SDLK_ESCAPE)
                        continuer = 0 ;
                    if (event.key.keysym.sym == SDLK_r)
                    {
                        recommencer = 1 ;
                        recalculer = 0;
                        continuer =0;
                    }
                    if (event.key.keysym.sym == SDLK_s)
                        SDL_SaveBMP(ecran , "Mandel_50.bmp" ); // Enregistrement de l'image dans un fichier .bmp

                    break;
                }
            }
            SDL_FreeSurface(rectangle); // Libération de la surface
        }
    }
    SDL_Quit();
    return EXIT_SUCCESS;

}
void petitMandel ()
{
    int x=0,y=0;
    SDL_Surface *ecran  ;
    ecran = SDL_GetVideoSurface();
    SDL_LockSurface(ecran);

    // trait rouge à droite de l'image
    for (j=5; j<=1044; j++)
    {
        x = LARGEUR_ECRAN +5 ;
        y = j ;
        placerPoint(ecran,x,y,SDL_MapRGB(ecran->format,200,0,0));
    }
    SDL_Flip(ecran);


//  instructions pour placer un petit Mandelbrot témoin dans la fenêtre "interactive"
    for ( j = 0 ; j < 600 ; j ++) // balayage vertical
    {
        yC = YDEBUT + (DELTA * j)/600;
        for ( i = 0 ; i < 600 ; i ++) // balayage horizontal
        {
            xC = XDEBUT + (DELTA * i)/600;
            n = 0 ; // initialisation du compteur de calcul
            xZ = 0 ;
            yZ = 0 ;
            xT = 0 ;
            while ( xZ*xZ + yZ*yZ < CONST_DIVERGENCE && n < 500)  /* boucle de calcul
                elle s'arretera si xZ²+yZ² >= 4 ou si on a atteint le maximum d'itérations*/
            {
                xT = xZ ;// variable temporaire pour le calcul de yZ
                xZ = xZ*xZ - yZ*yZ + xC ;
                yZ = 2*yZ*xT + yC ;
                n ++;
            }
            if (n< 500)
            {
                x = i + 1065 ; //  Coordonnées du point à placer
                y = j + 15;
                color = floor (255-255*log(1+n*255/500)/log(256)); // calcul pour un dégradé plus progressif*/
                placerPoint(ecran,x,y,SDL_MapRGB(ecran->format,color,color,color));
            }
        }
    }
    SDL_UnlockSurface(ecran);
    SDL_Flip(ecran);
}

void placerPoint(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
    int bpp = surface->format->BytesPerPixel;

    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

    switch(bpp)
    {
    case 1:
        *p = pixel;
        break;
    case 2:
        *(Uint16 *)p = pixel;
        break;
    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
        {
            p[0] = (pixel >> 16) & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = pixel & 0xff;
        }
        else
        {
            p[0] = pixel & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = (pixel >> 16) & 0xff;
        }
        break;
    case 4:
        *(Uint32 *)p = pixel;
        break;
    }
}

Solution

  • Looks like you're freeing your SDL_Surface pointer "rectangle" once extra on line 309. If you comment that line out it runs fine.

    When the code gets into the "SDL_MOUSEBUTTONUP" case of your switch statement, it frees the rectangle, then on line 309 it's freed again.