Утечки памяти и указатели - PullRequest
       108

Утечки памяти и указатели

0 голосов
/ 24 октября 2018

Я реализовал программу, которая суммирует элементы массива, используя потоки.Каждый поток добавляет элементы части массива и помещает его в массив.Наконец, другой поток подводит итог.

Эта программа, кажется, работает, НО у меня тонна утечек памяти, которую я не могу исправить.Я использую valgrind для обнаружения утечек памяти.Держу пари, что в моих знаниях указателей отсутствуют некоторые ключевые функции.

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

Теперь для некоторого кода:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#define MAX_RAND 100
/**
 * @brief global variables shared by threads
 *      array -> the array of values
 *      size-> the size of the array
 *      numberOfThreads -> the number of threads used to compute the sum
 * 
 */
int *array;
int size;
int numberOfThreads = 3;

/**
 * @brief each thread works on  disjoint segments of an array(i.e. two or more threads shall never work on the same segment). This
 * encapsulates the start and end indexes used by a thread.
 * 
 */
typedef struct
{
    int startIndex;
    int endIndex;
} wrapper;

/**
 * @brief this is used by the extra thread and contains the array of sums computed by the previous threads, along the size of the results
 * array
 * 
 */
typedef struct
{
    int *array;
    int size;
} resultsWrapper;

/**
 * @brief this computes the sum of a disjoint segment of the shared array
 * 
 * @param args 
 * @return void* 
 */
void *sum_runner(void *args)
{
    /**
     * @brief cast the argument and retrieve the indexes
     * 
     */
    wrapper *data = (wrapper *)args;
    int currentIndex = data->startIndex;
    int endIndex = data->endIndex;
    int *sum = (int *)malloc(sizeof(int *));
    *sum = 0;

    /**
     * @brief iterate that segment and compute the sum
     * 
     */
    while (currentIndex < endIndex)
    {
        *sum += array[currentIndex];
        currentIndex++;
    }

    /**
     * @brief return the sum
     * 
     */
    pthread_exit((void *)sum);
}

/**
 * @brief this is used by the an extra thread to sum up the elements computed by the previouse threads
 * 
 * @param args 
 * @return void* 
 */
void *results_sum_runner(void *args)
{
    /**
     * @brief cast the arguments and retrieve the array and its size
     * 
     */
    resultsWrapper *results = (resultsWrapper *)args;
    int size = results->size;
    int *array = results->array;
    int *sum = (int *)malloc(sizeof(int *));
    *sum = 0;

    /**
     * @brief sum its elements up
     * 
     */
    for (int i = 0; i < size; i++)
    {
        *sum += array[i];
    }

    free(results);
    free(array);

    /**
     * @brief return the result
     * 
     */
    pthread_exit((void *)sum);
}

/**
 * @brief populates the given vector with random numbers
 * 
 * @param array the target array
 * @param size the size of the array
 */
void populateWithRand(int *array, int size)
{
    for (int i = 0; i < size; i++)
    {
        array[i] = rand() % MAX_RAND;
    }
    printf("Finished populating vector\n");
}

/**
 * @brief this prints a given array
 * 
 * @param array the array to be printed
 * @param size the size of the array
 */
void printArray(int *array, int size)
{
    printf("Array: \n");
    for (int i = 0; i < size; i++)
    {
        printf("%d ", array[i]);
    }
    printf("\n");
}

/**
 * @brief this creates a normal partition, i.e. a partition containing size/threads elements
 * 
 * @param index the current index in array  
 * @param quotient the quotient
 * @return wrapper returns a new "pair"
 */
wrapper createNormalPartition(int index, int quotient)
{
    wrapper normalPartition;
    normalPartition.startIndex = index;
    normalPartition.endIndex = index + quotient - 1;
    printf("    Created normal partition (%d, %d)\n", normalPartition.startIndex, normalPartition.endIndex);
    return normalPartition;
}

/**
 * @brief this creates an overloaded partition, i.e. a partition containing size/threads+1 elements. We use overloaded partitions to spread
 * the load amongst r threads, where r is size%threads
 * 
 * @param index the current index in the array
 * @param quotient the quotient
 * @return wrapper returns a new "overloaded pair"
 */
wrapper createOverloadedPartition(int index, int quotient)
{
    wrapper normalPartition;
    normalPartition.startIndex = index;
    normalPartition.endIndex = index + quotient;
    printf("    Created normal partition (%d, %d)\n", normalPartition.startIndex, normalPartition.endIndex);
    return normalPartition;
}

/**
 * @brief core function. Splits the entire array by index to each thread
 * 
 * @return wrapper* returns an array of partitions to be used by threads
 */
wrapper *createPartitions()
{
    printf("Creating partitions......\n");
    /**
     * @brief compute the quotient, the remainder and initialize
     * 
     */
    int quotient = size / numberOfThreads;
    int remainder = size % numberOfThreads;
    int last = 0;

    /**
     * @brief create the array of partitions
     * 
     */
    wrapper *partitions = (wrapper *)malloc(sizeof(wrapper));

    /**
     * @brief populate the previously created array. If the we have a remainder, the last r threads will have an extra computation to perform.
     * 
     */
    for (int i = 0; i < numberOfThreads; i++)
    {
        /**
             * @brief check the current index and create the appropriate partitions
             * 
             */
        if (i < numberOfThreads - remainder)
        {
            partitions[i] = createNormalPartition(last, quotient);
            last += quotient;
            continue;
        }
        wrapper temp = createOverloadedPartition(last, quotient);

        partitions[i] = temp;
        last += quotient + 1;
    }
    printf("Finished creating partitions......\n");

    /**
     * @brief return the previously-populated partitions
     * 
     */
    return partitions;
}

/**
 * @brief this is a utility function. This creates the threads and assigns them the working partition
 * 
 * @param threads the array of threads
 */
void createThreads(pthread_t *threads)
{
    /**
     * @brief create a dummy wrapper to store the pairs at every step
     * 
     */
    wrapper *partitions = createPartitions();

    printf("Creating threads......\n");

    /**
     * @brief create some threads
     * 
     */
    for (int i = 0; i < numberOfThreads; i++)
    {
        pthread_create(&threads[i], NULL, sum_runner, (void *)&partitions[i]);
        printf("    Created thread %lu\n", threads[i]);
    }
    free(partitions);
    printf("Finished creating threads......\n");
}

/**
 * @brief this is a utility function. This performs join in the threads and stores the sums computed
 * 
 * @param threads the array of threads
 * @return int* the array of computed sums
 */
int *startThreads(pthread_t *threads)
{
    printf("Starting threads...\n");
    /**
     * @brief initialize local variables
     * 
     */
    int *temp;
    int *results = (int *)malloc(sizeof(int *) * numberOfThreads);

    /**
     * @brief performs join on threads and store the sums computed
     * 
     */
    for (int i = 0; i < numberOfThreads; i++)
    {
        temp = (int *)malloc(sizeof(temp));
        printf("    Starting thread %lu\n", threads[i]);
        pthread_join(threads[i], (void **)&temp);
        results[i] = *temp;
        free(temp);
    }

    printf("Exiting...\n");
    /**
     * @brief return the array of computed sums
     * 
     */
    return results;
}

/**
 * @brief this function calls the utility functions and computes the final sum using a separate thread
 * 
 * @return int 
 */
int run()
{
    /**
     * @brief create the threads ids array
     * 
     */
    int *results;
    int *finalResult;
    pthread_t *threads = (pthread_t *)malloc(sizeof(pthread_t *));
    pthread_t summingThread;

    /**
     * @brief pass the threads id's to create them
     * 
     */
    createThreads(threads);

    /**
     * @brief get the sums
     * 
     */
    results = startThreads(threads);

    /**
     * @brief print the array 
     * 
     */
    printArray(results, numberOfThreads);

    /**
     * @brief create a new thread and let him compute the final sum
     * 
     */
    resultsWrapper *resultData = (resultsWrapper *)malloc(sizeof(resultsWrapper *));
    resultData->size = numberOfThreads;
    resultData->array = results;

    /**
     * @brief add up the sums computed by the threads
     * 
     */
    pthread_create(&summingThread, NULL, results_sum_runner, (void *)resultData);
    pthread_join(summingThread, (void *)&finalResult);

    /**
     * @brief return the sum
     * 
     */
    free(threads);
    free(resultData);
    free(results);
    return *finalResult;
}

/**
 * @brief this is the entry point
 * 
 * @return int success
 */
int main()
{
    /**
     * @brief initialize variables, run the program and print the result
     * 
     */
    size = 47;
    array = calloc(sizeof(array), size);
    populateWithRand(array, size);
    printArray(array, size);
    int sum;
    sum = run();
    free(array);
    printf("Sum of the array is %d\n", sum);
}

Пример вывода:

Finished populating vector
Array:
83 86 77 15 93 35 86 92 49 21 62 27 90 59 63 26 40 26 72 36 11 68 67 29 82 30 62 23 67 35 29 2 22 58 69 67 93 56 11 42 29 73 21 19 84 37 98
Creating partitions......
    Created normal partition (0, 14)
    Created normal partition (15, 30)
    Created normal partition (31, 46)
Finished creating partitions......
Creating threads......
    Created thread 139720910055168
    Created thread 139720901662464
    Created thread 139720893269760
Finished creating threads......
Starting threads...
    Starting thread 139720910055168
    Starting thread 139720901662464
    Starting thread 139720893269760
Exiting...
Array:
875 674 683
Sum of the array is 2232

Отчет Valgrind:

==4725== Memcheck, a memory error detector
==4725== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.==4725== Using Valgrind-3.14.0.GIT and LibVEX; rerun with -h for copyright info==4725== Command: ./counter
==4725==Finished populating vector
Array:
83 86 77 15 93 35 86 92 49 21 62 27 90 59 63 26 40 26 72 36 11 68 67 29 82 30 62 23 67 35 29 2 22 58 69 67 93 56 11 42 29 73 21 19 84 37 98
Creating partitions......
    Created normal partition (0, 14)
    Created normal partition (15, 30)
==4725== Invalid write of size 8
==4725==    at 0x109505: createPartitions (counter.c:215)
==4725==    by 0x109550: createThreads (counter.c:238)
==4725==    by 0x10973A: run (counter.c:312)
==4725==    by 0x10985C: main (counter.c:367)
==4725==  Address 0x4a61698 is 0 bytes after a block of size 8 alloc'd
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x10948F: createPartitions (counter.c:195)
==4725==    by 0x109550: createThreads (counter.c:238)
==4725==    by 0x10973A: run (counter.c:312)
==4725==    by 0x10985C: main (counter.c:367)
==4725==
    Created normal partition (31, 46)
Finished creating partitions......
Creating threads......
    Created thread 90576640
==4725== Invalid write of size 8
==4725==    at 0x48812C8: pthread_create@@GLIBC_2.2.5 (in /usr/lib/libpthread-2.28.so)
==4725==    by 0x1095A8: createThreads (counter.c:248)
==4725==    by 0x10973A: run (counter.c:312)
==4725==    by 0x10985C: main (counter.c:367)
==4725==  Address 0x4a61648 is 0 bytes after a block of size 8 alloc'd
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x10972A: run (counter.c:305)
==4725==    by 0x10985C: main (counter.c:367)
==4725==
==4725== Invalid read of size 8
==4725==    at 0x1095BD: createThreads (counter.c:249)
==4725==    by 0x10973A: run (counter.c:312)
==4725==    by 0x10985C: main (counter.c:367)
==4725==  Address 0x4a61648 is 0 bytes after a block of size 8 alloc'd
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x10972A: run (counter.c:305)
==4725==    by 0x10985C: main (counter.c:367)
==4725==
    Created thread 98969344
    Created thread 107362048
==4725== Thread 3:
==4725== Invalid read of size 4
==4725==    at 0x1091F1: sum_runner (counter.c:52)
==4725==    by 0x4880A9C: start_thread (in /usr/lib/libpthread-2.28.so)
==4725==    by 0x4995B22: clone (in /usr/lib/libc-2.28.so)
==4725==  Address 0x4a61698 is 0 bytes after a block of size 8 alloc'd
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x10948F: createPartitions (counter.c:195)
==4725==    by 0x109550: createThreads (counter.c:238)
==4725==    by 0x10973A: run (counter.c:312)
==4725==    by 0x10985C: main (counter.c:367)
==4725==
==4725== Invalid read of size 4
==4725==    at 0x1091FA: sum_runner (counter.c:53)
==4725==    by 0x4880A9C: start_thread (in /usr/lib/libpthread-2.28.so)
==4725==    by 0x4995B22: clone (in /usr/lib/libc-2.28.so)
==4725==  Address 0x4a6169c is 4 bytes after a block of size 8 alloc'd
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x10948F: createPartitions (counter.c:195)
==4725==    by 0x109550: createThreads (counter.c:238)
==4725==    by 0x10973A: run (counter.c:312)
==4725==    by 0x10985C: main (counter.c:367)
==4725==
Finished creating threads......
Starting threads...
    Starting thread 90576640
==4725== Thread 1:
==4725== Invalid read of size 8
==4725==    at 0x10966B: startThreads (counter.c:278)
==4725==    by 0x109746: run (counter.c:318)
==4725==    by 0x10985C: main (counter.c:367)
==4725==  Address 0x4a61648 is 0 bytes after a block of size 8 alloc'd
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x10972A: run (counter.c:305)
==4725==    by 0x10985C: main (counter.c:367)
==4725==
    Starting thread 98969344
==4725== Invalid read of size 8
==4725==    at 0x109696: startThreads (counter.c:279)
==4725==    by 0x109746: run (counter.c:318)
==4725==    by 0x10985C: main (counter.c:367)
==4725==  Address 0x4a61648 is 0 bytes after a block of size 8 alloc'd
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x10972A: run (counter.c:305)
==4725==    by 0x10985C: main (counter.c:367)
==4725==
    Starting thread 107362048
Exiting...
Array:
875 674 683
==4725== Invalid write of size 4
==4725==    at 0x109777: run (counter.c:331)
==4725==    by 0x10985C: main (counter.c:367)
==4725==  Address 0x4a62508 is 0 bytes after a block of size 8 alloc'd
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x109768: run (counter.c:330)
==4725==    by 0x10985C: main (counter.c:367)
==4725==
==4725== Thread 2:
==4725== Invalid read of size 4
==4725==    at 0x10926E: results_sum_runner (counter.c:87)
==4725==    by 0x4880A9C: start_thread (in /usr/lib/libpthread-2.28.so)
==4725==    by 0x4995B22: clone (in /usr/lib/libc-2.28.so)
==4725==  Address 0x4a62508 is 0 bytes after a block of size 8 alloc'd
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x109768: run (counter.c:330)
==4725==    by 0x10985C: main (counter.c:367)
==4725==
==4725== Thread 1:
==4725== Invalid free() / delete / delete[] / realloc()
==4725==    at 0x48389AB: free (vg_replace_malloc.c:530)
==4725==    by 0x1097CE: run (counter.c:346)
==4725==    by 0x10985C: main (counter.c:367)
==4725==  Address 0x4a62500 is 0 bytes inside a block of size 8 free'd
==4725==    at 0x48389AB: free (vg_replace_malloc.c:530)
==4725==    by 0x1092DB: results_sum_runner (counter.c:101)
==4725==    by 0x4880A9C: start_thread (in /usr/lib/libpthread-2.28.so)
==4725==    by 0x4995B22: clone (in /usr/lib/libc-2.28.so)
==4725==  Block was alloc'd at
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x109768: run (counter.c:330)
==4725==    by 0x10985C: main (counter.c:367)
==4725==
==4725== Invalid free() / delete / delete[] / realloc()
==4725==    at 0x48389AB: free (vg_replace_malloc.c:530)
==4725==    by 0x1097DA: run (counter.c:347)
==4725==    by 0x10985C: main (counter.c:367)
==4725==  Address 0x4a61b20 is 0 bytes inside a block of size 24 free'd
==4725==    at 0x48389AB: free (vg_replace_malloc.c:530)
==4725==    by 0x1092E7: results_sum_runner (counter.c:102)
==4725==    by 0x4880A9C: start_thread (in /usr/lib/libpthread-2.28.so)
==4725==    by 0x4995B22: clone (in /usr/lib/libc-2.28.so)
==4725==  Block was alloc'd at
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x109638: startThreads (counter.c:269)
==4725==    by 0x109746: run (counter.c:318)
==4725==    by 0x10985C: main (counter.c:367)
==4725==
Sum of the array is 2232
==4725==
==4725== HEAP SUMMARY:
==4725==     in use at exit: 1,652 bytes in 8 blocks
==4725==   total heap usage: 21 allocs, 15 frees, 3,996 bytes allocated
==4725==
==4725== LEAK SUMMARY:
==4725==    definitely lost: 32 bytes in 4 blocks
==4725==    indirectly lost: 0 bytes in 0 blocks
==4725==      possibly lost: 0 bytes in 0 blocks
==4725==    still reachable: 1,620 bytes in 4 blocks
==4725==         suppressed: 0 bytes in 0 blocks
==4725== Rerun with --leak-check=full to see details of leaked memory
==4725==
==4725== For counts of detected and suppressed errors, rerun with: -v
==4725== ERROR SUMMARY: 20 errors from 11 contexts (suppressed: 0 from 0)

Ответы [ 2 ]

0 голосов
/ 24 октября 2018

Конечно, здесь есть некоторые утечки памяти, но более насущная проблема - это множественные случаи чтения / записи после окончания выделенной памяти и двойного освобождения.

Давайте рассмотрим ихвремя, начинающееся сверху:

==4725== Invalid write of size 8
==4725==    at 0x109505: createPartitions (counter.c:215)
==4725==    by 0x109550: createThreads (counter.c:238)
==4725==    by 0x10973A: run (counter.c:312)
==4725==    by 0x10985C: main (counter.c:367)
==4725==  Address 0x4a61698 is 0 bytes after a block of size 8 alloc'd
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x10948F: createPartitions (counter.c:195)
==4725==    by 0x109550: createThreads (counter.c:238)
==4725==    by 0x10973A: run (counter.c:312)
==4725==    by 0x10985C: main (counter.c:367)
==4725==

Это жалоба на запись того, что было выделено.Вот код, который выполняет как распределение, так и недопустимый доступ:

wrapper *partitions = (wrapper *)malloc(sizeof(wrapper));

for (int i = 0; i < numberOfThreads; i++)
{
    if (i < numberOfThreads - remainder)
    {
        partitions[i] = createNormalPartition(last, quotient);
        last += quotient;
        continue;
    }
    wrapper temp = createOverloadedPartition(last, quotient);

    partitions[i] = temp;
    last += quotient + 1;
}

Вы выделяете пространство для одного экземпляра wrapper, но записываете его так, как если бы оно быломассив numberOfThreads экземпляров.Вам нужно выделить место для этого множества экземпляров:

wrapper *partitions = malloc(sizeof(wrapper) * numberOfThreads);

Следующий:

==4725== Invalid write of size 8
==4725==    at 0x48812C8: pthread_create@@GLIBC_2.2.5 (in /usr/lib/libpthread-2.28.so)
==4725==    by 0x1095A8: createThreads (counter.c:248)
==4725==    by 0x10973A: run (counter.c:312)
==4725==    by 0x10985C: main (counter.c:367)
==4725==  Address 0x4a61648 is 0 bytes after a block of size 8 alloc'd
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x10972A: run (counter.c:305)
==4725==    by 0x10985C: main (counter.c:367)
==4725==
==4725== Invalid read of size 8
==4725==    at 0x1095BD: createThreads (counter.c:249)
==4725==    by 0x10973A: run (counter.c:312)
==4725==    by 0x10985C: main (counter.c:367)
==4725==  Address 0x4a61648 is 0 bytes after a block of size 8 alloc'd
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x10972A: run (counter.c:305)
==4725==    by 0x10985C: main (counter.c:367)
==4725==

Другая недопустимая запись вместе с недопустимым чтением.Вот распределение в run:

pthread_t *threads = (pthread_t *)malloc(sizeof(pthread_t *));

И чтение / запись в createThreads:

for (int i = 0; i < numberOfThreads; i++)
{
    pthread_create(&threads[i], NULL, sum_runner, (void *)&partitions[i]);
    printf("    Created thread %lu\n", threads[i]);
}

Как и раньше, вы выделяете пространство для сингла экземпляр, а не массив.Кроме того, вы выделяете место для pthread_t * вместо pthread_t, который, вероятно, будет слишком маленьким.Измените выделение, чтобы освободить место для массива, и используйте тип объекта, а не тип указателя:

pthread_t *threads = malloc(sizeof(pthread_t) * numberOfThreads);

Далее:

==4725== Invalid read of size 4
==4725==    at 0x1091F1: sum_runner (counter.c:52)
==4725==    by 0x4880A9C: start_thread (in /usr/lib/libpthread-2.28.so)
==4725==    by 0x4995B22: clone (in /usr/lib/libc-2.28.so)
==4725==  Address 0x4a61698 is 0 bytes after a block of size 8 alloc'd
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x10948F: createPartitions (counter.c:195)
==4725==    by 0x109550: createThreads (counter.c:238)
==4725==    by 0x10973A: run (counter.c:312)
==4725==    by 0x10985C: main (counter.c:367)
==4725==
==4725== Invalid read of size 4
==4725==    at 0x1091FA: sum_runner (counter.c:53)
==4725==    by 0x4880A9C: start_thread (in /usr/lib/libpthread-2.28.so)
==4725==    by 0x4995B22: clone (in /usr/lib/libc-2.28.so)
==4725==  Address 0x4a6169c is 4 bytes after a block of size 8 alloc'd
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x10948F: createPartitions (counter.c:195)
==4725==    by 0x109550: createThreads (counter.c:238)
==4725==    by 0x10973A: run (counter.c:312)
==4725==    by 0x10985C: main (counter.c:367)
==4725==

Пара недопустимых операций чтения, происходящих из одного и того жеразмещение и доступ в аджентных линиях.Это то же недействительное распределение из первого сообщения, которое мы уже рассмотрели.Следующий:

==4725== Thread 1:
==4725== Invalid read of size 8
==4725==    at 0x10966B: startThreads (counter.c:278)
==4725==    by 0x109746: run (counter.c:318)
==4725==    by 0x10985C: main (counter.c:367)
==4725==  Address 0x4a61648 is 0 bytes after a block of size 8 alloc'd
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x10972A: run (counter.c:305)
==4725==    by 0x10985C: main (counter.c:367)
==4725==
    Starting thread 98969344
==4725== Invalid read of size 8
==4725==    at 0x109696: startThreads (counter.c:279)
==4725==    by 0x109746: run (counter.c:318)
==4725==    by 0x10985C: main (counter.c:367)
==4725==  Address 0x4a61648 is 0 bytes after a block of size 8 alloc'd
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x10972A: run (counter.c:305)
==4725==    by 0x10985C: main (counter.c:367)
==4725==

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

==4725== Invalid write of size 4
==4725==    at 0x109777: run (counter.c:331)
==4725==    by 0x10985C: main (counter.c:367)
==4725==  Address 0x4a62508 is 0 bytes after a block of size 8 alloc'd
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x109768: run (counter.c:330)
==4725==    by 0x10985C: main (counter.c:367)
==4725==
==4725== Thread 2:
==4725== Invalid read of size 4
==4725==    at 0x10926E: results_sum_runner (counter.c:87)
==4725==    by 0x4880A9C: start_thread (in /usr/lib/libpthread-2.28.so)
==4725==    by 0x4995B22: clone (in /usr/lib/libc-2.28.so)
==4725==  Address 0x4a62508 is 0 bytes after a block of size 8 alloc'd
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x109768: run (counter.c:330)
==4725==    by 0x10985C: main (counter.c:367)

Недопустимое чтение и запись, происходящие из одного и того же размещения.Вот распределение в run:

resultsWrapper *resultData = (resultsWrapper *)malloc(sizeof(resultsWrapper *));

Чтение в results_sum_runner:

resultsWrapper *results = (resultsWrapper *)args;
int size = results->size;

И запись в run:

resultData->size = numberOfThreads;

Здесь вы выделяете пространство для указателя на resultsWrapper, а не экземпляра из resultsWrapper.Исправьте распределение следующим образом:

resultsWrapper *resultData = malloc(sizeof(resultsWrapper));

Следующее:

==4725== Invalid free() / delete / delete[] / realloc()
==4725==    at 0x48389AB: free (vg_replace_malloc.c:530)
==4725==    by 0x1097CE: run (counter.c:346)
==4725==    by 0x10985C: main (counter.c:367)
==4725==  Address 0x4a62500 is 0 bytes inside a block of size 8 free'd
==4725==    at 0x48389AB: free (vg_replace_malloc.c:530)
==4725==    by 0x1092DB: results_sum_runner (counter.c:101)
==4725==    by 0x4880A9C: start_thread (in /usr/lib/libpthread-2.28.so)
==4725==    by 0x4995B22: clone (in /usr/lib/libc-2.28.so)
==4725==  Block was alloc'd at
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x109768: run (counter.c:330)
==4725==    by 0x10985C: main (counter.c:367)
==4725==

Вот двойное освобождение.Выделение и второй free находятся в run:

resultsWrapper *resultData = (resultsWrapper *)malloc(sizeof(resultsWrapper *));
resultData->size = numberOfThreads;
resultData->array = results;

pthread_create(&summingThread, NULL, results_sum_runner, (void *)resultData);
pthread_join(summingThread, (void *)&finalResult);

free(threads);
free(resultData);
free(results);

И вот первое free в results_sum_runner:

void *results_sum_runner(void *args)
{
    resultsWrapper *results = (resultsWrapper *)args;
    int size = results->size;
    int *array = results->array;
    int *sum = (int *)malloc(sizeof(int *));
    *sum = 0;

    for (int i = 0; i < size; i++)
    {
        *sum += array[i];
    }

    free(results);
    free(array);

    pthread_exit((void *)sum);
}

Здесь вы выделяете память дляresultData и передача его в функцию потока results_sum_runner.Этот поток освобождает память, но затем - и вызывающий поток.Удалите либо free(resultData) в run или free(results) в results_sum_runner.

Последний:

==4725== Invalid free() / delete / delete[] / realloc()
==4725==    at 0x48389AB: free (vg_replace_malloc.c:530)
==4725==    by 0x1097DA: run (counter.c:347)
==4725==    by 0x10985C: main (counter.c:367)
==4725==  Address 0x4a61b20 is 0 bytes inside a block of size 24 free'd
==4725==    at 0x48389AB: free (vg_replace_malloc.c:530)
==4725==    by 0x1092E7: results_sum_runner (counter.c:102)
==4725==    by 0x4880A9C: start_thread (in /usr/lib/libpthread-2.28.so)
==4725==    by 0x4995B22: clone (in /usr/lib/libc-2.28.so)
==4725==  Block was alloc'd at
==4725==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==4725==    by 0x109638: startThreads (counter.c:269)
==4725==    by 0x109746: run (counter.c:318)
==4725==    by 0x10985C: main (counter.c:367)
==4725==

Еще один двойной аналог, похожий на последний.free(results) в run и free(array) в results_sum_runner относятся к одной и той же памяти, поэтому избавьтесь от одного из них.

Теперь, если мы скомпилируем эти изменения и снова запустим под valgrind, мы получимЕще одна проблема:

==24305== Invalid read of size 4
==24305==    at 0x40090E: sum_runner (x1.c:52)
==24305==    by 0x4E416B9: start_thread (pthread_create.c:333)
==24305==  Address 0x54216a8 is 8 bytes inside a block of size 24 free'd
==24305==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==24305==    by 0x400CEF: createThreads (x1.c:251)
==24305==    by 0x400E3C: run (x1.c:312)
==24305==    by 0x400F5C: main (x1.c:367)
==24305==  Block was alloc'd at
==24305==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==24305==    by 0x400B98: createPartitions (x1.c:195)
==24305==    by 0x400C57: createThreads (x1.c:238)
==24305==    by 0x400E3C: run (x1.c:312)
==24305==    by 0x400F5C: main (x1.c:367)
==24305== 
==24305== Invalid read of size 4
==24305==    at 0x400917: sum_runner (x1.c:53)
==24305==    by 0x4E416B9: start_thread (pthread_create.c:333)
==24305==  Address 0x54216ac is 12 bytes inside a block of size 24 free'd
==24305==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==24305==    by 0x400CEF: createThreads (x1.c:251)
==24305==    by 0x400E3C: run (x1.c:312)
==24305==    by 0x400F5C: main (x1.c:367)
==24305==  Block was alloc'd at
==24305==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==24305==    by 0x400B98: createPartitions (x1.c:195)
==24305==    by 0x400C57: createThreads (x1.c:238)
==24305==    by 0x400E3C: run (x1.c:312)
==24305==    by 0x400F5C: main (x1.c:367)
==24305== 

Здесь у нас есть пара операций чтения из уже освобожденного блока памяти.Чтения происходят в sum_runner:

wrapper *data = (wrapper *)args;
int currentIndex = data->startIndex;
int endIndex = data->endIndex;

, а в createThreads:

for (int i = 0; i < numberOfThreads; i++)
{
    pthread_create(&threads[i], NULL, sum_runner, (void *)&partitions[i]);
    printf("    Created thread %lu\n", threads[i]);
}
free(partitions);

Судя по вашим комментариям в другом месте кода, вы, кажется, под впечатлениемэтот вызов pthread_join запускает поток.Это не вариант.Вызов pthread_create фактически запускает поток, в то время как pthread_join говорит вызывающему потоку дождаться завершения данного потока.Таким образом, вы в конечном итоге освобождаете эту память до того, как поток сможет ее использовать.

Так что удалите эту free и измените createThreads, чтобы вернуть этот указатель.Затем в run (откуда вызывается createThreads) и сделайте здесь бесплатное после вызова startThreads (который действительно должен быть переименован во что-то вроде waitForThreadsToFinish):

wrapper *createThreads(pthread_t *threads)
{
    wrapper *partitions = createPartitions();

    printf("Creating threads......\n");

    for (int i = 0; i < numberOfThreads; i++)
    {
        pthread_create(&threads[i], NULL, sum_runner, (void *)&partitions[i]);
        printf("    Created thread %lu\n", threads[i]);
    }
    // remove free
    printf("Finished creating threads......\n");
    return partitions;
}

...

int run() 
{
    ...

    wrapper *partitions = createThreads(threads);
    results = startThreads(threads);
    free(partitions);

Иэто должно заботиться о недопустимых доступах.

Есть также несколько мест, где вы выделяете пространство для int * (или массива int *), где вы должны выделить место для одного или нескольких int.Это не вызывает проблем в вашей системе, потому что int * по крайней мере такой же большой, как int, но вы все равно должны использовать правильный тип независимо от того.

Также обратите внимание, что мои предложенные изменения удалилиприведение к возвращаемому значению malloc.См. Я приведу результат malloc? для более подробной информации.

Есть еще несколько утечек памяти, которые вы можете найти, если передадите --leak-check=full в valgrind, но я оставлю это в качестве упражнения для читателя.

0 голосов
/ 24 октября 2018

Исправьте ваши invalid write с, прежде чем искать утечки.

Во-первых, в createPartitions вы выделяете память для partitions, но достаточно только для хранения одного wrapper

wrapper *partitions = (wrapper *)malloc(sizeof(wrapper));

Затем у вас есть цикл выполнения numberOfThreads times (3) и его копирование в вышеуказанный массив.Вторая и последующие записи находятся за пределами массива и вызывают invalid write.

Вам необходимо выделить больше памяти для partitions, например,

wrapper *partitions = (wrapper *)malloc(numberOfThreads*sizeof(wrapper));
...