简体   繁体   中英

Data corruption in malloc'ed memory

When ever I try to access data in memory that I've acquired using malloc , the data is corrupted

I'm writing a program that reads Linux directories and writes the names of the files and sub-directories in a "string array" (char** array in c). It operates using dirent.h functionalities like readdir() . readdir returns a dirent structure that has a dname[256] that's the name of a file/sub-directory in the target directory. I equate the dirent string(char*) to an index of a malloced position in a char** array

I basically have a walk_path() function that reads the directory entries and writes their names into a malloced location then return that location

data_t* walk_path(char* path) {
    int size = 0;

    if(path == NULL){
        printf("NULL path\n");
        return NULL;
    }
    struct dirent* entry;
    DIR* dir_l = opendir(path);

    if(dir_l == NULL) {
        char** data = (char**)malloc(sizeof(char*) * 2);
        data[0] = path;
        data_t* ret = (data_t*)malloc(sizeof(data_t));
        ret->data = data;
        ret->size = 1;
        return ret;
    }

    while((entry = readdir(dir_l)) != NULL) {
        if(!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
            continue;
        size++;
    }
    closedir(dir_l);

    char** data = (char**)malloc(sizeof(char*) * size + 1);
    int loop_v = 0;
    dir_l = opendir(path);

    while((entry = readdir(dir_l)) != NULL && loop_v < size) {
        if(!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
            continue;
        data[loop_v] = entry->d_name;
        loop_v++;
    }

    closedir(dir_l);

    data_t* ret = (data_t*)malloc(sizeof(data_t*));
    ret->size = (size_t)size;
    ret->data = data;
    return ret;
}

and a merge path function that can take two directories and write their data into a single array

char** merge_path(char* path, char* path2) {
    data_t* path_data = walk_path(path);
    data_t* path2_data = walk_path(path2);
    if(path_data == NULL || path2_data == NULL) {
        printf("Merge failed, couldn't get path data\n");
        return NULL;
    }

    char** new_dir_info = (char**)malloc(sizeof(char*) * (path2_data->size + path_data->size) );
    if(new_dir_info == NULL)
        return NULL;

    int loop = 0;
    while(loop < path_data->size) {
        new_dir_info[loop] = path_data->data[loop];
        loop++;
    }
    loop = 0;
    while(loop < path2_data->size) {
        new_dir_info[loop + path_data->size] = path2_data->data[loop];
        loop++;
    }
    free(path_data);
    free(path2_data);
    return new_dir_info;
}

The char** array that the merge path function returns always has corrupted data, that is the characters in the character arrays are corrupted and not the pointers themselves, though I expect it to have the strings passed to it from the directory entries it instead has random strings.

I've stepped through the code and found that the data gets corrupted in merge path function, the source of the error could still originate from walk_path() .

This

   data_t* ret = (data_t*)malloc(sizeof(data_t*));

ought to be

   data_t* ret = (data_t*)malloc(sizeof(data_t));

Generally in C void -pointers do not need to be casted, so all casts to malloc in your code can be dropped, which made the above line look like:

   data_t* ret = malloc(sizeof(data_t*));

More over to rule out bugs like this one better step away from doubling the type to malloc ate inside the call to malloc() , but better use the variable to allocate to along with the dereferencing operator, like this:

   data_t* ret = malloc(sizeof *ret);

Also this line

    data[loop_v] = entry->d_name;

copies a pointer to the entry name, not the name itself.

Consider using

   data[loop_v] = strdup(entry->d_name);

which dynamically allocates room for a copy of where entry->d_name points to.

Alternatively instead of

   char**data;

define

   char (*data)[sizeof entry->d_name]; /* Array of pointers to char[as many char as entry->d_name is defined to have] */

or

   char (*data)[sizeof ((struct dirent*)NULL)->d_name]; /* Array of pointers to char[as many char as entry->d_name is defined to have] */

and allocate to it like this (following the above proposed pattern):

   data = malloc((size /* + 1 */) * sizeof *data); /* Not sure what the idea behind this +1 is. */

And instead of

   data[loop_v] = strdup(entry->d_name);

do

   strcpy(data[loop_v], entry->d_name);

If going this route you need to adjust the definition of data_t.data accordingly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM