简体   繁体   中英

Freeing pointer to a structure of pointers

I have a situation that I can't seem to resolve. It is causing a slow, but over time disastrous memory leak. I noticed that even though I am freeing a structure of pointers (which I passed to a function), I forgot to free the pointers inside them self, which according to valgrind leads to memory leaks. I have tried to free the memory of the pointers from within the function, but I can't seem to resolve the error message error: request for member 'xxx' in something not a structure or union .

This is a short overview of my program. I am creating a data structure that holds variables required for a threaded function. There is a main function where arguments are passed to, and depending on the data it fills in the appropriate structure. Then it launches a thread of the actual function (passing the structure as a void pointer), in which I take and recreate the actual structure inside the function. This is the code:

void cmd_test(char *sender, char **args, int arg_count) {
    char command[1024];

    // creates my exec pointer structure
    exec_struct *exec = malloc(sizeof(exec_struct));

    // adds a thread identifier to a struct to keep track of threads
    exec->tID = thread_add(EXEC);

    // the first malloc which I don't know how to free
    exec->sender = malloc(sizeof(char) * strlen(sender) + 1);
    sprintf(exec->sender, "%s", sender);

    // move ahead 5 arguments (there will always be 5 or more arguments supplied
    // by the calling function)
    args += 5;
    memset(command, 0, sizeof(command));

    // concatenate the remaining arguments into a cstring
    while(*args[0]) {
        printf("arg: %s\n", *args);
        sprintf(command, "%s %s", command, *args);
        args++;
    }

    // the second malloc which I don't know how to free
    exec->exec = malloc(sizeof(char) * strlen(command) + 1);

    // copy the string to the structure from pointer+1 to end of pointer
    // removes a space created from the first iteration of previous loop)
    sprintf(exec->exec, "%s", command + 1);

    printf("command:%s\n exec:%s\n", command, exec->exec);

    //stores an actual thread id into a struct of threads to keep track of 
    //the actual thread (other one is just to keep track of what type
    //of thread is running)
    threads[exec->tID].tID = Thread_Start(exec_cmd, exec);
}

This is how I set up my structure with some comments on what's happening. Thread_Start() is just a function that accepts a function address and a structure address to pass to the threaded function. This is the exec_cmd function:

void *exec_cmd(void *param) {
    char buf[1024];
    FILE *command;

    // recreate the structure locally inside the thread
    exec_struct exec = *((exec_struct *)param);

    // causes the error described
    // free(param.exec);
    // free(param.sender);

    // free the structure memory from the thread creating function.
    free(param);

    memset(buf,0,1024);
    sprintf(buf,"%s",exec.exec);
    command = popen(buf,"r");

    while(!feof(command)) {
        memset(buf,0,1024);
        fgets(buf,1024,command);
        printf("%s\n", buff);
        sleep(1);
    }

    pclose(command);

    // cleans itself up from the tracking structures
    thread_remove(EXEC, 0);

    // exits cleanly
    return NULL;
}

To resolve the error I have tried to cast the structure in front of it but the error still persists. Using the -> operator leads to a void* deference error.

I also removed some of the bulk from the functions such as checking to see if a thread is already running and error checking for reduced clutter. The functions both work in my application (it creates the thread stores it fine and it's passing and creating the new structure perfectly and it's executing the passed command). It's just that I can't figure out how to free the two malloc calls I made from inside the thread. How can I resolve this issue?

exec_struct exec = *((exec_struct *)param);

//free(param.exec);
//free(param.sender);

param is the void * passed in. Your structure copy is called exec .

You perhaps meant:

free(exec.exec);
free(exec.sender);

Beware however, that you promptly access exec.exec later in the same function. You can't do that if you've already free'd it. Copying the struct does not mean you have copied the memory the pointers point to.

This line:

sprintf(buf,"%s",exec.exec);

Needs to happen before exec.exec is free'd.

The general principle is that you start at the "deepest" level in the structure, and work your way up. Never ever let something at an "upper" layer be freed until everything inside it is freed. In other words, use the opposite order of which you called malloc.

I don't really see the point of doing:

exec_struct exec = *((exec_struct *)param);

I would just copy the original pointer:

exec_struct *exec = (exec_struct *)param;

Then

free(exec->sender); 
free(exec->command);

free(exec);

Of course, you should not do ANY of the freeing until you have finished using the exec structure.

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