вывод valgrind: недопустимый free() при остановке программы

#c #pointers #malloc #valgrind #free

#c #указатели #malloc #valgrind #Бесплатно

Вопрос:

Я хотел бы реализовать приложение, которое отвечает за параллельное выполнение нескольких задач.

Перед добавлением реальных задач я попытался установить базу, но программа возвращает различные ошибки при выполнении valgrind.

 ==4827== Thread 3:
==4827== Invalid free() / delete / delete[] / realloc()
==4827==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4827==    by 0x400E31: my_handler (in /home/test)
==4827==    by 0x4E416F9: start_thread (pthread_create.c:333)
==4827==  Address 0x5420070 is 48 bytes inside a block of size 96 free'd
==4827==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4827==    by 0x400E31: my_handler (in /home/test)
==4827==    by 0x4E416F9: start_thread (pthread_create.c:333)
==4827==  Block was alloc'd at
==4827==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4827==    by 0x400B75: main (in /home/test)
==4827== 
==4827== Thread 1:
==4827== Invalid read of size 8
==4827==    at 0x400CD3: main (in /home/test)
==4827==  Address 0x5420068 is 40 bytes inside a block of size 96 free'd
==4827==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4827==    by 0x400E31: my_handler (in /home/test)
==4827==    by 0x4E416F9: start_thread (pthread_create.c:333)
==4827==  Block was alloc'd at
==4827==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4827==    by 0x400B75: main (in /home/test)
==4827== 
==4827== Invalid read of size 8
==4827==    at 0x400CFF: main (in /home/test)
==4827==  Address 0x5420068 is 40 bytes inside a block of size 96 free'd
==4827==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4827==    by 0x400E31: my_handler (in /home/test)
==4827==    by 0x4E416F9: start_thread (pthread_create.c:333)
==4827==  Block was alloc'd at
==4827==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4827==    by 0x400B75: main (in /home/test)
==4827== 
==4827== Invalid read of size 8
==4827==    at 0x400D30: main (in /home/test)
==4827==  Address 0x5420060 is 32 bytes inside a block of size 96 free'd
==4827==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4827==    by 0x400E31: my_handler (in /home/test)
==4827==    by 0x4E416F9: start_thread (pthread_create.c:333)
==4827==  Block was alloc'd at
==4827==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4827==    by 0x400B75: main (in /home/test)
==4827== 
tstop
==4827== Invalid write of size 8
==4827==    at 0x400D5B: main (in /home/test)
==4827==  Address 0x5420068 is 40 bytes inside a block of size 96 free'd
==4827==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4827==    by 0x400E31: my_handler (in /home/test)
==4827==    by 0x4E416F9: start_thread (pthread_create.c:333)
==4827==  Block was alloc'd at
==4827==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4827==    by 0x400B75: main (in /home/test)
==4827== 
tstop
==4827== Invalid free() / delete / delete[] / realloc()
==4827==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4827==    by 0x400D8C: main (in /home/test)
==4827==  Address 0x5420040 is 0 bytes inside a block of size 96 free'd
==4827==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4827==    by 0x400E31: my_handler (in /home/test)
==4827==    by 0x4E416F9: start_thread (pthread_create.c:333)
==4827==  Block was alloc'd at
==4827==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4827==    by 0x400B75: main (in /home/test)
==4827== 
==4827== 
==4827== HEAP SUMMARY:
==4827==     in use at exit: 1,614 bytes in 4 blocks
==4827==   total heap usage: 9 allocs, 7 frees, 3,334 bytes allocated
==4827== 
==4827== LEAK SUMMARY:
==4827==    definitely lost: 0 bytes in 0 blocks
==4827==    indirectly lost: 0 bytes in 0 blocks
==4827==      possibly lost: 0 bytes in 0 blocks
==4827==    still reachable: 1,614 bytes in 4 blocks
==4827==         suppressed: 0 bytes in 0 blocks
  

Я предполагаю, что эти ошибки связаны с доступом к памяти, которая уже освобождена, и недопустимым free().
Однако я не могу понять, как и почему они происходят.

 typedef int (*init)();
typedef int (*launch)();
typedef int (*stop)();

typedef struct stTask stTask_t;
typedef struct stEngine stEngine_t;

struct stTask
{
    char        name[10];    
    init        initTask;
    launch      launchTask;
    stop        stopTask; 
    pthread_t   tId;
};

struct stEngine
{
   int16_t  NbTasks;
   stTask_t* TaskThread;
};

static void sig_handler(int signo);
static int tinit(void);
static int tlaunch(void);
static int tstop(void);
static void* my_handler(void* params);

stTask_t array[] =
{
    {"TEST", (init)tinit, (launch)tlaunch, (stop)tstop, 0},
    {"TEST2", (init)tinit, (launch)tlaunch, (stop)tstop, 0}
};

int exitReq;
stEngine_t engine;

int main (int argc, char *argv[])
{
    struct sigaction action;
    int i;
    exitReq = 0;
    memset(amp;engine, 0, sizeof(stEngine_t));
    engine.NbTasks = 2;

    memset(amp;action, '', sizeof(action));
    action.sa_handler = amp;sig_handler;
    sigfillset(amp;action.sa_mask);
    action.sa_flags = 0;
    if ((sigaction(SIGTERM, amp;action, NULL) != 0) || (sigaction(SIGINT,  amp;action, NULL) != 0)) {
        exit(EXIT_FAILURE);
    }

    engine.TaskThread = malloc(engine.NbTasks * sizeof(stTask_t));

    for (i = 0; i < engine.NbTasks; i  ) {
        engine.TaskThread[i] = array[i];
        engine.TaskThread[i].initTask();
        pthread_create(amp;engine.TaskThread[i].tId, NULL, my_handler, (void *) amp;engine.TaskThread[i]);
    }

    while (!exitReq) {
        //... do stuff
        sched_yield();
    }       

    for (i = 0; i < engine.NbTasks; i  ) {
        (void)pthread_cancel(engine.TaskThread[i].tId);
        pthread_join(engine.TaskThread[i].tId, NULL);
        engine.TaskThread[i].stopTask();
        engine.TaskThread[i].tId = 0;
    }
    free(engine.TaskThread);
    memset(amp;engine, 0, sizeof(stEngine_t));          
    return 0;
}

static void sig_handler(int signo) 
{
    if (signo == SIGINT || signo == SIGTERM) {
        exitReq = 1;
    }
}

static void* my_handler(void* params)
{
    stTask_t* ptask = (stTask_t*) params;

    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

    while (!exitReq) {
        ptask->launchTask();
        pthread_testcancel();
    }
    free(ptask);
    pthread_exit(NULL);
}

static int tinit(void)
{
    fprintf(stdout, "%sn", __func__);
    return 0;
}

static int tlaunch(void)
{
    fprintf(stdout, "%sn", __func__);
    return 0;
}

static int tstop(void)
{
    fprintf(stdout, "%sn", __func__);
    return 0;
}
  

Добавив комментарий в функцию обработки: я не получил ошибки, но несколько байтов все еще выделяются при ручной остановке программы.

     //free(ptask);
  

Я не получаю ошибки, но при ручной остановке программы все еще выделяется несколько байтов.
По мере необходимости я передаю адрес структуры в качестве последнего параметра pthread_create, но, вероятно, я что-то неправильно понимаю в памяти

 ==6017== HEAP SUMMARY:
==6017==     in use at exit: 1,614 bytes in 4 blocks
==6017==   total heap usage: 9 allocs, 5 frees, 3,334 bytes allocated
==6017== 
==6017== LEAK SUMMARY:
==6017==    definitely lost: 0 bytes in 0 blocks
==6017==    indirectly lost: 0 bytes in 0 blocks
==6017==      possibly lost: 0 bytes in 0 blocks
==6017==    still reachable: 1,614 bytes in 4 blocks
==6017==         suppressed: 0 bytes in 0 blocks
  

Может ли кто-нибудь объяснить мне, почему в обоих случаях память освобождается неправильно?

Комментарии:

1. Вы выполняете один malloc (в основном) для выделения массива, а затем множество free вызовов (в дочерних потоках) для каждого элемента в выделенном массиве. Это неверно. Каждый malloc должен иметь ровно один, free и этому free должно быть присвоено точное значение, возвращаемое malloc . Кроме того, основной поток также освобождает весь массив. Так что это тоже двойное освобождение.

2. @kaylum Спасибо! Кажется, это решает проблему