“free():无效的下一个大小(快)”malloc中的错误

时间:2014-12-17 07:56:14

标签: c malloc free

我在malloc/free遇到了问题。我想实现一个简单的'ls'来显示dir中的未隐藏文件。

这是我的代码:

void do_ls(char *dirname, _Bool ls_list) {
    DIR *dir_ptr;
    const char * d_name;
    struct dirent *direntp, ** dirarray;
    int fcnt, d_name_max;
    if((dir_ptr = opendir(dirname))==NULL) {
        fprintf(stderr,"ls: cannot open %s\n", dirname);
        exit(-1);
    }
    else {
        fcnt = 0; // count unhidden files
        d_name_max = -1; // max length of filename
        while((direntp = readdir(dir_ptr))!=NULL) {
            d_name = direntp->d_name;
            if(d_name[0]!='.' ||\
                    strcmp(d_name, ".")==0 ||\
                    strcmp(d_name, "..")==0) {
                fcnt++;
                if((int)strlen(d_name)>d_name_max)
                    d_name_max = strlen(d_name);
            }
        }
        // use a array to store dirent printer
        dirarray = (struct dirent**)malloc(sizeof(struct dirent *)*fcnt);
        // reset read position
        seekdir(dir_ptr, 0);
        int i = 0;
        while((direntp=readdir(dir_ptr))!=NULL) {
            if(d_name[0]!='.' ||\
                    strcmp(d_name, ".")==0 ||\
                    strcmp(d_name, "..")==0) {
                dirarray[i++] = direntp; // save pointer
            }
        }
        qsort(dirarray, fcnt, sizeof(struct dirent*), alphacmp); // qsort for lexicographical ordering
        for(int i=0;i<fcnt;i++)
            fprintf(stdout, "%s\n", dirarray[i]->d_name); // print result
        if(dirarray!=NULL)
            free(dirarray); // free if not NULL
        closedir(dir_ptr);
    }
}

这对我来说很困惑,在某些情况下会起作用或崩溃。我想在do_ls中肯定会有一些错误,但仍然无法找到。

我的目录下的文件是:

`ls -a ~/file/c/`
./  ../  1*  a.c  db/  mpi/  test1.c  .test1.c.swo  .test1.c.swp  unix/  .ycm_extra_conf.py  .ycm_extra_conf.pyc    

但是当运行./my-own-ls ~/file/c/时,我遇到了这些错误:

/home/panhzh3/file/c:
..
.test1.c.swo
.test1.c.swp
.ycm_extra_conf.py
.ycm_extra_conf.pyc
1
mpi
unix
*** glibc detected *** ./ls: free(): invalid next size (fast): 0x08d9b028 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x75b12)[0xb7664b12]
./ls[0x80488e5]
./ls[0x8048a6f]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb76084d3]
./ls[0x8048621]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:0a 1183201    /home/panhzh3/file/c/unix/hw/ls
08049000-0804a000 r--p 00000000 08:0a 1183201    /home/panhzh3/file/c/unix/hw/ls
0804a000-0804b000 rw-p 00001000 08:0a 1183201    /home/panhzh3/file/c/unix/hw/ls
08d93000-08dbc000 rw-p 00000000 00:00 0          [heap]
b75b4000-b75d0000 r-xp 00000000 08:09 392702     /lib/i386-linux-gnu/libgcc_s.so.1
b75d0000-b75d1000 r--p 0001b000 08:09 392702     /lib/i386-linux-gnu/libgcc_s.so.1
b75d1000-b75d2000 rw-p 0001c000 08:09 392702     /lib/i386-linux-gnu/libgcc_s.so.1
b75ee000-b75ef000 rw-p 00000000 00:00 0 
b75ef000-b7793000 r-xp 00000000 08:09 392617     /lib/i386-linux-gnu/libc-2.15.so
b7793000-b7795000 r--p 001a4000 08:09 392617     /lib/i386-linux-gnu/libc-2.15.so
b7795000-b7796000 rw-p 001a6000 08:09 392617     /lib/i386-linux-gnu/libc-2.15.so
b7796000-b7799000 rw-p 00000000 00:00 0 
b77b3000-b77b7000 rw-p 00000000 00:00 0 
b77b7000-b77b8000 r-xp 00000000 00:00 0          [vdso]
b77b8000-b77d8000 r-xp 00000000 08:09 392601     /lib/i386-linux-gnu/ld-2.15.so
b77d8000-b77d9000 r--p 0001f000 08:09 392601     /lib/i386-linux-gnu/ld-2.15.so
b77d9000-b77da000 rw-p 00020000 08:09 392601     /lib/i386-linux-gnu/ld-2.15.so
bff21000-bff43000 rw-p 00000000 00:00 0          [stack]
[2]    32254 abort (core dumped)  ./ls ~/file/c

源代码:

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>

int alphacmp(const void * a, const void * b) {
    struct dirent ** ta = (struct dirent**)a;
    struct dirent ** tb = (struct dirent**)b;
    return strcmp((*ta)->d_name, (*tb)->d_name);
}

void do_ls(char *dirname, _Bool ls_list) {
    DIR *dir_ptr;
    const char * d_name;
    struct dirent *direntp, ** dirarray;
    int fcnt, d_name_max;
    if((dir_ptr = opendir(dirname))==NULL) {
        fprintf(stderr,"ls2: cannot open %s\n", dirname);
        exit(-1);
    }
    else {
        fcnt = 0;
        d_name_max = -1;
        while((direntp = readdir(dir_ptr))!=NULL) {
            d_name = direntp->d_name;
            if(d_name[0]!='.' ||\
                    strcmp(d_name, ".")==0 ||\
                    strcmp(d_name, "..")==0) {
                fcnt++;
                if((int)strlen(d_name)>d_name_max)
                    d_name_max = strlen(d_name);
            }
        }
        dirarray = (struct dirent**)malloc(sizeof(struct dirent *)*fcnt);
        seekdir(dir_ptr, 0);
        int i = 0;
        while((direntp=readdir(dir_ptr))!=NULL) {
            if(d_name[0]!='.' ||\
                    strcmp(d_name, ".")==0 ||\
                    strcmp(d_name, "..")==0) {
                dirarray[i++] = direntp;
            }
        }
        qsort(dirarray, fcnt, sizeof(struct dirent*), alphacmp);
        for(int i=0;i<fcnt;i++)
            fprintf(stdout, "%s\n", dirarray[i]->d_name);
        if(dirarray!=NULL)
            free(dirarray);
        closedir(dir_ptr);
    }
}

int main(int argc, char **argv) {
    const char * const short_options = "l";
    const struct option long_options[] = {
       {"list", 0, NULL, 'l'},
       {NULL, 0, NULL, 0},
    };
    const char * program_name = argv[0];

    opterr = 0;

    int next_option;
    _Bool ls_list = false;

    do {
        next_option = getopt_long(argc, argv, short_options, long_options, NULL);
        switch(next_option) {
            case 'l':
                ls_list = true;
                break; 
            case '?':
                fprintf(stderr, "Invalid option: -%c", optopt);
                exit(-1);
                break;
            case ':':
                fprintf(stderr, "Option -%c needs argument.", optopt);
            case -1:
                break;
            default:
                abort();
        }
    } while(next_option!=-1);

    if(optind == argc)
        do_ls(".", ls_list);
    else
        for(;optind<argc;optind++) {
            printf("%s:\n", argv[optind]);
            do_ls(argv[optind], ls_list);
        }
    return 0;
}

1 个答案:

答案 0 :(得分:1)

在你的第二个while循环中,你错过了这一行:

d_name = direntp->d_name;

您可能需要知道的另一件事是,您不能依赖于将dirent指针存储在数组中并对它们进行排序。 readdir的手册页说明后续调用可能会覆盖数据,因此您可能需要复制每个条目并对副本进行排序。