*** Error in `./a.out': double free or corrupt

2019-09-21 20:47发布

问题:

I get the following error when running a c program:

*** Error in `./a.out': double free or corruption (!prev): 0x0000000000bb0470 ***

I believe this is due to fclose() being called in the program, It is a Lexical Analyzer for compilers in c language and it uses file pointers . Here is code:

    #include<stdio.h>
#include<string.h>

typedef struct Terminal_table
{
    int index;  
    char symbol[10],indicator;      
}Terminal_table;

typedef struct  Identifier_table
{
    int index;  
    char name[10];      
}Identifier_table;

typedef struct Literal_table
{   
    int SR,name,precision;  
    char base[10],scale[10];        
}Literal_table;

typedef struct Uniform_symbol_table
{   
    int SR,index;   
    char name[10],symbol_class[10];
}Uniform_symbol_table;

int main()
{
    FILE *fp_PGM,*fp_TT,*fp_LT,*fp_UST,*fp_IT,*fp_IT1,*fp_LT1;

    Terminal_table TT;  
    Identifier_table IT,IT1;
    Literal_table LT,LT1;   
    Uniform_symbol_table UST;

    int i=0,flag,flag_IT,flag_LT,a;     
    char ch,buffer[10];

    fp_PGM=fopen("PGM_LEX.txt","r");
    fp_UST=fopen("UST.TXT","w");
    fp_IT=fopen("IT.TXT","w");
    fp_LT=fopen("LT.TXT","w");

    UST.SR=1;   
    IT.index=1; 
    LT.SR=1;

    for(i=0;i<10;i++)
        buffer[i]='\0';
    i=0;

    while(!feof(fp_PGM))
    {
        ch=fgetc(fp_PGM);
        if(isalpha(ch) || isdigit(ch))
            buffer[i++]=ch;

        else if(ch!='"')
        {
            flag=0;
            fp_TT=fopen("TT.txt","r");
            while(!feof(fp_TT))
            {
                fscanf(fp_TT,"%d %s %c\n",&TT.index,&TT.symbol,&TT.indicator);
                if(strcmp(TT.symbol,buffer)==0)
                {
                    flag=1;
                    strcpy(UST.name,buffer);    
                    UST.index=TT.index;
                    if(TT.indicator=='Y')
                        strcpy(UST.symbol_class,"TRM");
                    else    
                        strcpy(UST.symbol_class,"KEY");
                    fprintf(fp_UST,"%d %s %s %d \n",UST.SR++,UST.name,UST.symbol_class,UST.index);
                    break;
                }
            }
            fclose(fp_TT);
            if(flag==0)
            {
                if(isalpha(buffer[0]))
                {
                    flag_IT=0;  
                    fclose(fp_IT);
                    fp_IT1=fopen("IT.TXT","r");
                    while(!feof(fp_IT1))
                    {
                        fscanf(fp_IT1,"%d %s\n",&IT1.index,IT1.name);
                        if(strcmp(IT1.name,buffer)==0)
                        {
                            flag_IT=1;  
                            break;
                        }
                    }
                    fclose(fp_IT1);     
                    strcpy(UST.name,buffer);
                    UST.index=TT.index; 
                    strcpy(UST.symbol_class,"IDN");

                    if(flag_IT==1)
                        fprintf(fp_UST,"%d %s %s %d \n",UST.SR++,UST.name,UST.symbol_class,IT1.index);
                    if(flag_IT==0)
                    {
                        fp_IT=fopen("IT.TXT","a");
                        strcpy(IT.name,buffer);
                        fprintf(fp_IT,"%d %s\n",IT.index++,IT.name);
                        fprintf(fp_UST,"%d %s %s %d \n",UST.SR++,UST.name,UST.symbol_class,IT.index-1);
                        fclose(fp_IT);
                    }
                }
                else if(isdigit(buffer[0]))
                {
                    flag_LT=0;
                    fclose(fp_LT);
                    fp_LT=fopen("LT.TXT","r");
                    while(!feof(fp_LT))
                    {
                        fscanf(fp_LT,"%d %d %s %s %s\n",&LT1.SR,&LT1.name,&LT1.precision,&LT1.base,&LT1.scale);
                        a=atoi(buffer);
                        if(LT1.name==a)
                        {
                            flag_LT=1;  
                            break;
                        }
                    }
                    fclose(fp_LT);
                    strcpy(UST.name,buffer);
                    UST.index=TT.index;
                    strcpy(UST.symbol_class,"LIT");
                    if(flag_LT==1)
                        fprintf(fp_UST,"%d %s %s %d \n",UST.SR++,UST.name,UST.symbol_class,LT1.SR);
                    if(flag_LT==0)
                    {
                        fclose(fp_LT);
                        fp_LT=fopen("LT.TXT","a");
                        LT.name=atoi(buffer);
                        LT.precision=2; 
                        strcpy(LT.base,"DECIMAL");
                        strcpy(LT.scale,"FIXED");
                        strcpy(UST.name,buffer);
                        fprintf(fp_LT,"%d %d %d %s %s\n",LT.SR++,LT.name,LT.precision,LT.base,LT.scale);
                        fprintf(fp_UST,"%d %s %s %d \n",UST.SR++,UST.name,UST.symbol_class,LT.SR-1);
                        fclose(fp_LT);
                    }
                }
            }
            for(i=0;i<10;i++)
                buffer[i]='\0';
            buffer[0]=ch;
            fp_TT=fopen("TT.txt","r");
            while(!feof(fp_TT))
            {
                fscanf(fp_TT,"%d %s %c\n",&TT.index,&TT.symbol,&TT.indicator);
                if(strcmp(TT.symbol,buffer)==0)
                {
                    strcpy(UST.name,buffer);
                    UST.index=TT.index;
                    strcpy(UST.symbol_class,"TRM");
                    fprintf(fp_UST,"%d %s %s %d \n",UST.SR++,UST.name,UST.symbol_class,UST.index);
                    break;
                }
            }
            for(i=0;i<10;i++)       
                buffer[i]='\0';
            fclose(fp_TT);
            i=0;
        }
        else if(ch=='"')
        {
            buffer[0]=ch;
            fp_TT=fopen("TT.txt","r");
            while(!feof(fp_TT))
            {
                fscanf(fp_TT,"%d %s %c\n",&TT.index,&TT.symbol,&TT.indicator);
                if(strcmp(TT.symbol,buffer)==0)
                {
                    strcpy(UST.name,buffer);
                    UST.index=TT.index;
                    if(TT.indicator=='Y')
                        strcpy(UST.symbol_class,"TRM");
                    else
                        strcpy(UST.symbol_class,"KEY");
                    fprintf(fp_UST,"%d %s %s %d \n",UST.SR++,UST.name,UST.symbol_class,UST.index);
                    break;
                }
            }
            fclose(fp_TT);      
            ch=fgetc(fp_PGM);
            while(ch!='"')
            {
                ch=fgetc(fp_PGM);
            }
            strcpy(UST.name,buffer);    
            UST.index=TT.index;
            if(TT.indicator=='Y')
                strcpy(UST.symbol_class,"TRM");
            else    
                strcpy(UST.symbol_class,"KEY");
            fprintf(fp_UST,"%d %s %s %d \n",UST.SR++,UST.name,UST.symbol_class,UST.index);
            ch=fgetc(fp_PGM);
        }
    }
    fclose(fp_PGM); 
    fclose(fp_UST);     
    fclose(fp_IT);      
    fclose(fp_LT);
}

Error in `./a.out': double free or corruption (!prev): 0x0000000000bb0470

there are multiple files operations in this program it includes source program (it is simple c program without preprocessors), Terminal tale as input and this text files need to be already created before running above code

TT.txt =>

1   void    N
2   main    N
3   int N
4   float   N
5   printf  N
6   scanf   N
7   ,   Y
8   ;   Y
9   =   Y
10  "   Y
11  {   Y
12  }   Y
13  *   Y
14  /   Y
15      +       Y
16  -   Y
17  (   Y
18  )   Y
19  <   Y
20  >   Y
21  getch   N

PGM_LEX.txt =>

void main()
{
    int i=10,j;
    printf("%d",i);
    i=(j/10);
    getch();        
}

thanks!

回答1:

Beside other problems, valgrind reports

==27338== Invalid read of size 4
==27338==    at 0x4EA57D4: fclose@@GLIBC_2.2.5 (in /usr/lib64/libc-2.26.so)
==27338==    by 0x400B32: main (gggg4.c:135)
==27338==  Address 0x5211310 is 0 bytes inside a block of size 552 free'd
==27338==    at 0x4C2DD18: free (vg_replace_malloc.c:530)
==27338==    by 0x4EA587D: fclose@@GLIBC_2.2.5 (in /usr/lib64/libc-2.26.so)
==27338==    by 0x400AFB: main (gggg4.c:127)
==27338==  Block was alloc'd at
==27338==    at 0x4C2CB6B: malloc (vg_replace_malloc.c:299)
==27338==    by 0x4EA622C: __fopen_internal (in /usr/lib64/libc-2.26.so)
==27338==    by 0x400E00: main (gggg4.c:116)

These two lines are

127                     fclose(fp_LT);
...
135                             fclose(fp_LT);


回答2:

As @ensc mentioned, in line 135 of your code, in the if(flag_LT==0) case, you call fclose(fp_LT), but you already closed it in line 127.

The tool cppcheck also finds this bug.

Instead of repeatedly opening and closing the same file, you can use rewind() to go back to the start of a file. Also, your program is not checking the result of any of the fopen(), fscanf() and fclose() calls. That means that if you have corrupted data, or there are any errors reading and writing the files, your program will ignore these errors, with possibly bad consequences.



回答3:

This section looks suspicious:

                fclose(fp_LT);              // fp_LT is closed
                strcpy(UST.name,buffer);
                UST.index=TT.index;
                strcpy(UST.symbol_class,"LIT");
                if(flag_LT==1)
                    fprintf(fp_UST,"%d %s %s %d \n",UST.SR++,UST.name,UST.symbol_class,LT1.SR);
                if(flag_LT==0)
                {
                    fclose(fp_LT);            // fp_LT is closed again

In case flag_LT is zero, it seems you call fclose twice. That is undefined behavior.