I'm having a memory leak issue with a thread. I would like to free the dat array and the buff array when the thread is cancelled or otherwise exits normally. My problem seems to be that the free call in my pthread_cleanup stack isn't executing. I know that my stack is working because my other cleanup handler function works. Any insight into what's happening here? One thought I have is to create another cleanup handler function to free things but that seems inefficient.
static void *dat_col(void *arg) {
struct args *prof = (struct args *)arg;
char *dat = NULL;
char *buff = NULL;
time_t start_t = 0;
time_t cur_t = 0;
int ret = 0;
struct timespec timeout;
clock_gettime(CLOCK_REALTIME, &timeout);
timeout.tv_sec += (60 * prof->interval);
pthread_cleanup_push(cleanup_handler, &prof->fc);
pthread_cleanup_push(free, (void *) dat);
pthread_cleanup_push(free, (void *) buff);
dat = malloc(50 * prof->points);
if (dat == NULL) {
perror("memory error");
goto fail;
}
memset(dat, 0, 50 * prof->points);
buff = malloc(2);
if (buff == NULL) {
perror("memory error");
goto fail;
}
memset(buff, 0, 2);
time(&start_t);
ret = write_port(prof->fd, "OPC?;PRES;\r", 11);
if (ret < 0)
goto fail;
ret = read_port(prof->fd, buff, 2);
if (ret < 0) {
goto fail;
}
switch (prof->time_flag) {
case 0:
while (!exit_flag) {
pthread_testcancel();
ret = get_DATA(prof->fd, dat, prof->points, prof->chan, prof->fstar,
prof->fstop, &prof->fc);
if (ret < 0)
goto fail;
memset(dat, 0, 50*prof->points);
pthread_mutex_lock(&wait);
pthread_cond_timedwait(&cond, &wait, &timeout);
pthread_mutex_unlock(&wait);
timeout.tv_sec += (60 * prof->interval);
}
break;
case 1:
while ((difftime(start_t, cur_t) < (60 * prof->testtime)) && (!(exit_flag))) {
pthread_testcancel();
ret = get_DATA(prof->fd, dat, prof->points, prof->chan, prof->fstar,
prof->fstop, &prof->fc);
if (ret < 0)
goto fail;
memset(dat, 0, 50*prof->points);
pthread_mutex_lock(&wait);
pthread_cond_timedwait(&cond, &wait, &timeout);
pthread_mutex_unlock(&wait);
timeout.tv_sec += (60 * prof->interval);
time(&cur_t);
}
break;
}
fail:
pthread_cleanup_pop(1);
pthread_cleanup_pop(1);
pthread_cleanup_pop(prof->fc);
pthread_exit(NULL);
}
Remember that you push values onto the cleanup stack. And when you push the values, they are null pointers, which is the values being pushed.
One solution is to use your own "free" function, and push pointers to the variables instead. Like e.g.
void free_indirect(void *indirect_ptr)
{
free(*((void **) indirect_ptr));
}
// ...
pthread_cleanup_push(free_indirect, &dat);