ПроблемаУтечка памяти для конкретного потока происходит, когда динамически выделенная память для конкретного потока не освобождается до конца потока.
Для создания системы хранения данных, зависящей от потока, обычно выполняются следующие действия:
Создается ключ для хранения данных, специфичных для потоков.
Вы создаете нити.
В каждом потоке вы выделяете хранилище динамически, а затем связываете ключ с этим хранилищем.
После сопоставления сохраненные данные можно будет прочитать позже с помощью ключа.
Перед окончанием потока освободите специфическую для потока память с помощью клавиши.
Средство проверки помечает пути выполнения в потоке, где отсутствует последний шаг.
Средство проверки работает с этими семействами функций:
РискДанные, хранящиеся в памяти, доступны другим процессам даже после окончания потоков (утечка памяти). Помимо уязвимостей безопасности, утечки памяти могут уменьшить объем доступной памяти и снизить производительность.
ЗафиксироватьОсвободить динамически выделяемую память до конца потока.
Можно явно освободить динамически выделенную память с помощью таких функций, как free.
Кроме того, при создании ключа можно связать функцию деструктора с ключом. Функция деструктора вызывается со значением ключа в качестве аргумента в конце потока. В теле функции деструктора можно освободить любую память, связанную с ключом. При использовании этого метода функция поиска ошибок по-прежнему помечает дефект. Игнорировать этот дефект с соответствующими комментариями. См. раздел Результаты анализа пространства адресов с помощью исправлений ошибок или обоснований.
Пример - Память не освобождается в конце потока#include <threads.h>
#include <stdlib.h>
/* Global key to the thread-specific storage */
tss_t key;
enum { MAX_THREADS = 3 };
int add_data(void) {
int *data = (int *)malloc(2 * sizeof(int));
if (data == NULL) {
return -1; /* Report error */
}
data[0] = 0;
data[1] = 1;
if (thrd_success != tss_set(key, (void *)data)) {
/* Handle error */
}
return 0;
}
void print_data(void) {
/* Get this thread's global data from key */
int *data = tss_get(key);
if (data != NULL) {
/* Print data */
}
}
int func(void *dummy) {
if (add_data() != 0) {
return -1; /* Report error */
}
print_data();
return 0;
}
int main(void) {
thrd_t thread_id[MAX_THREADS];
/* Create the key before creating the threads */
if (thrd_success != tss_create(&key, NULL)) {
/* Handle error */
}
/* Create threads that would store specific storage */
for (size_t i = 0; i < MAX_THREADS; i++) {
if (thrd_success != thrd_create(&thread_id[i], func, NULL)) {
/* Handle error */
}
}
for (size_t i = 0; i < MAX_THREADS; i++) {
if (thrd_success != thrd_join(thread_id[i], NULL)) {
/* Handle error */
}
}
tss_delete(key);
return 0;
}В этом примере функция запуска каждого потока func вызывает две функции:
В точках, где func возвращает, динамически выделенное хранилище не освобождено.
Исправление - свободная динамически выделяемая память явноОдной из возможных корректировок является явное освобождение динамически выделяемой памяти перед выходом из функции запуска потока. См. выделенные изменения в исправленной версии.
В этой исправленной версии дефект все еще появляется на return оператор в разделе обработки ошибок func. Дефект не может возникнуть на практике, поскольку раздел обработки ошибок вводится только в случае сбоя динамического выделения памяти. Проигнорируйте этот оставшийся дефект с соответствующими комментариями. См. раздел Результаты анализа пространства адресов с помощью исправлений ошибок или обоснований.
#include <threads.h>
#include <stdlib.h>
/* Global key to the thread-specific storage */
tss_t key;
enum { MAX_THREADS = 3 };
int add_data(void) {
int *data = (int *)malloc(2 * sizeof(int));
if (data == NULL) {
return -1; /* Report error */
}
data[0] = 0;
data[1] = 1;
if (thrd_success != tss_set(key, (void *)data)) {
/* Handle error */
}
return 0;
}
void print_data(void) {
/* Get this thread's global data from key */
int *data = tss_get(key);
if (data != NULL) {
/* Print data */
}
}
int func(void *dummy) {
if (add_data() != 0) {
return -1; /* Report error */
}
print_data();
free(tss_get(key));
return 0;
}
int main(void) {
thrd_t thread_id[MAX_THREADS];
/* Create the key before creating the threads */
if (thrd_success != tss_create(&key, NULL)) {
/* Handle error */
}
/* Create threads that would store specific storage */
for (size_t i = 0; i < MAX_THREADS; i++) {
if (thrd_success != thrd_create(&thread_id[i], func, NULL)) {
/* Handle error */
}
}
for (size_t i = 0; i < MAX_THREADS; i++) {
if (thrd_success != thrd_join(thread_id[i], NULL)) {
/* Handle error */
}
}
tss_delete(key);
return 0;
}