Pb 与 C 程序:双重释放或损坏 (!prev)

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

几年前,Benoit Mandelbrot 去世后,我决定做一个小程序来计算并看看他著名的分形集。很多年前我就做过(用turbo pascal语言)——这段时间,微积分花了一个晚上。所以我决定学一点C语言。有了 code::blocks 和 SDL 库(以及许多帮助),我终于编写了一个程序,我可以看到集合,并用鼠标放大内部。 效果很好,我还不到 windows。做同样的工作只需要 5 秒钟,而不是一晚上的微积分。

最近我决定发现linux,安装了与SDL相同的IDE。程序编译正常。它开始 运行,然后突然,当我使用鼠标时(左键上下单击 select 要放大的新方形区域),程序停止。

消息是:

double free or corruption (!prev)

st运行ge 的事情是,当我 运行 windows 下的代码时,它从未发生过。所以这对我来说是一件神秘的事情。我不知道这里的双重 免费腐败 是什么意思。

为了更好的帮助你最终可以发给我,我加入了程序的代码(不完美)。也许有人可以找到问题所在... 该程序是为在 1680x1050 像素的屏幕上显示而编写的。

#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;
    }
}

看起来你在第 309 行额外释放了你的 SDL_Surface 指针 "rectangle" 一次。如果你评论那条线它运行正常。

当代码进入 switch 语句的 "SDL_MOUSEBUTTONUP" 情况时,它释放矩形,然后在第 309 行再次释放它。

你已经完成了运行 tableauX(如果有机会,可能还有 tableauY)。在它们之前放置断言:

assert(j < LARGEUR_ECRAN);
tableauY[j] = yC;

在所有访问前放一个断言(你的程序中有6个)。

我这样做了,但以下断言失败了

assert(position.x < LARGEUR_ECRAN)
xTemp1 = tableauX [position.x];

断言失败意味着 position.x >= LARGEUR_ECRAN。实际上它是1243,而LARGEUR_ECRAN是1050。注意,第一次越界访问不一定会失败,这就是为什么它不会在position.x到达时立即发生1050.

另请注意,在一个系统上 运行 "successfully"(即使存在错误)可能会在另一个系统上崩溃。

编辑:实际上,user5071535 似乎为您的错误消息找到了更有可能的来源,但我可能在这里发现了一个不同的错误。

未分配指针或非 NULL 指针上的每个 free() 都会 return 此错误。在尝试任何 free() 之前,请确认指针是否已分配或等于 NULL。无论如何,任何在未分配的指针或 improperly/insufficient 分配的指针上工作的尝试都会 return 这个错误。在 Windows 下,事情发生的情况有所不同,这只是 "lucky" 的问题:错误的代码将不可避免地在 "random" 时间在任何平台上失败。抱歉英语不好。