Освобождение указателя на структуру указателей

У меня возникла ситуация, которую я никак не могу решить. Это вызывает медленную, но со временем катастрофическую утечку памяти. Я заметил, что, хотя я освобождаю структуру указателей (которую я передал функции), я забыл освободить указатели внутри них, что, согласно valgrind, приводит к утечкам памяти. Я попытался освободить память указателей из функции, но не могу устранить сообщение об ошибке error: request for member 'xxx' in something not a structure or union.

Это краткий обзор моей программы. Я создаю структуру данных, которая содержит переменные, необходимые для многопотоковой функции. Есть основная функция, которой передаются аргументы, и в зависимости от данных она заполняет соответствующую структуру. Затем он запускает поток фактической функции (передавая структуру как указатель void), в котором я беру и воссоздаю фактическую структуру внутри функции. Это код:

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

Вот как я настроил свою структуру с некоторыми комментариями о том, что происходит. Thread_Start() — это просто функция, которая принимает адрес функции и адрес структуры для передачи функции с нитями. Это функция exec_cmd:

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

Чтобы устранить ошибку, я попытался создать структуру перед ней, но ошибка все еще сохраняется. Использование оператора -> приводит к ошибке void* deference.

Я также удалил некоторые из функций, таких как проверка того, запущен ли уже поток, и проверка ошибок для уменьшения беспорядка. Обе функции работают в моем приложении (он создает поток, сохраняет его в порядке, отлично передает и создает новую структуру и выполняет переданную команду). Просто я не могу понять, как освободить два вызова malloc, которые я сделал внутри потока. Как я могу решить эту проблему?


person randy newfield    schedule 25.12.2012    source источник
comment
while(!feof(command)) {} всегда неправильно.   -  person wildplasser    schedule 25.12.2012


Ответы (2)


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

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

param — это переданный void *. Ваша копия структуры называется exec.

Возможно, вы имели в виду:

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

Однако имейте в виду, что вы сразу же получите доступ к exec.exec позже в той же функции. Вы не можете этого сделать, если уже освободили его. Копирование структуры не означает, что вы скопировали память, на которую указывают указатели.

Эта строка:

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

Это должно произойти до того, как exec.exec будет освобожден.

person JasonD    schedule 25.12.2012
comment
я пытался освободить исходную структуру, которую я выделил в первой функции. Что на самом деле происходит, когда я передаю указатели из структуры, которую я передал, в новую копию, которую я сделал, и я просто освобождаю старую структуру данных через free(param)? если да, то если я free(param), а затем free(exec.xxxx) в конце функции, все ли будет освобождено? если это так, то это имеет смысл для меня сейчас, если нет, не могли бы вы объяснить немного больше. - person randy newfield; 25.12.2012
comment
По сути, да. exec — это копия структуры, которая будет включать указатели на память, которую вы выделили. Таким образом, вы можете освободить param, так как вы больше на него не ссылаетесь, но вам нужно сохранить exec.***, пока вы не закончите с ними, а затем вы можете free и их тоже. - person JasonD; 25.12.2012
comment
спасибо за это это помогло выделить. хотя я снова запустил valgrind, и каждый раз, когда я создаю поток, он возвращается как ==11079== 136 bytes in 1 blocks are possibly lost in loss record 4 of 4 ==11079== at 0x402425F: calloc (vg_replace_malloc.c:467) ==11079== by 0x4010D2B: _dl_allocate_tls (dl-tls.c:300) ==11079== by 0x40432E2: pthread_create@@GLIBC_2.1 (allocatestack.c:561) ==11079== by 0x80491AB: Thread_Start (project.c:217), как я могу узнать, правда ли это и почему это может происходить. я не делаю никаких вызовов malloc для создания потоков. все остальные утечки устранены - person randy newfield; 25.12.2012

Общий принцип заключается в том, что вы начинаете с «самого глубокого» уровня структуры и продвигаетесь вверх. Никогда не позволяйте освобождать что-либо на «верхнем» уровне, пока не будет освобождено все, что находится внутри него. Другими словами, используйте порядок, противоположный тому, который вы назвали malloc.

Не вижу смысла делать:

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

Я бы просто скопировал исходный указатель:

exec_struct *exec = (exec_struct *)param;

Затем

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

free(exec);

Конечно, вы не должны делать НИЧЕГО освобождения, пока не закончите использовать структуру exec.

person Mats Petersson    schedule 25.12.2012