Не удается закрыть файлы или освободить динамическую память, когда они больше не нужны
Не удается закрыть файлы или освободить динамическую память, когда они больше не нужны.[1]
Эта проверка проверяет на наличие следующих проблем:
Утечка памяти.
Утечка ресурсов.
Утечка памяти для конкретного потока.
Утечка памяти происходит, когда вы не освобождаете блок памяти, выделенный через malloc, calloc, realloc, или new. Если память выделена в функции, дефект не возникает, если:
В рамках функции вы освобождаете память, используя free или delete.
Функция возвращает указатель, назначенный malloc, calloc, realloc, или new.
Функция сохраняет указатель в глобальной переменной или в параметре.
Динамические функции выделения памяти, такие как malloc выделите память на куче. Если вы не освобождаете память после использования, вы уменьшаете объем памяти, доступный для другого выделения. В встраиваемых системах с ограниченной памятью вы можете в конечном итоге исчерпать доступную память в куче даже во время выполнения программы.
Определите возможности, в которой осуществляется доступ к динамически выделенной памяти. Освободите блок памяти в конце этих возможностей.
Чтобы освободить блок памяти, используйте free функция на указателе, который использовался во время выделения памяти. Для образца:
ptr = (int*)malloc(sizeof(int)); //... free(ptr);
Это хорошая практика - выделять и освобождать память в том же модуле на том же уровне абстракции. Например, в этом примере func выделяет и освобождает память на том же уровне, но func2 не делает.
void func() {
ptr = (int*)malloc(sizeof(int));
{
...
}
free(ptr);
}
void func2() {
{
ptr = (int*)malloc(sizeof(int));
...
}
free(ptr);
}#include<stdlib.h>
#include<stdio.h>
void assign_memory(void)
{
int* pi = (int*)malloc(sizeof(int));
if (pi == NULL)
{
printf("Memory allocation failed");
return;
}
*pi = 42;
/* Defect: pi is not freed */
}В этом примере pi динамически распределяется по malloc. Функция assign_memory не освобождает память и не возвращается pi.
Одной из возможных коррекций является освобождение памяти, на которую ссылаются pi использование free функция. The free функция должна быть вызвана перед функцией assign_memory заканчивается
#include<stdlib.h>
#include<stdio.h>
void assign_memory(void)
{
int* pi = (int*)malloc(sizeof(int));
if (pi == NULL)
{
printf("Memory allocation failed");
return;
}
*pi = 42;
/* Fix: Free the pointer pi*/
free(pi);
}Еще одна возможная коррекция - вернуть указатель мыши pi. Возврат pi позволяет выполнять вызов функции assign_memory чтобы освободить блок памяти с помощью pi.
#include<stdlib.h>
#include<stdio.h>
int* assign_memory(void)
{
int* pi = (int*)malloc(sizeof(int));
if (pi == NULL)
{
printf("Memory allocation failed");
return(pi);
}
*pi = 42;
/* Fix: Return the pointer pi*/
return(pi);
}Утечка ресурсов происходит, когда вы открываете поток файлов при помощи FILE указатель, но не закрывайте его раньше:
Конец возможностей указателя.
Назначение указателя другому потоку.
Если вы не отпустите указатели на файлы явным образом как можно скорее, может возникнуть отказ из-за истощения ресурсов.
Закройте FILE указатель до конца его возможностей или до назначения указателя другому потоку.
FILE Указатель не выпущен до конца возможностей#include <stdio.h>
void func1( void ) {
FILE *fp1;
fp1 = fopen ( "data1.txt", "w" );
fprintf ( fp1, "*" );
fp1 = fopen ( "data2.txt", "w" );
fprintf ( fp1, "!" );
fclose ( fp1 );
}В этом примере указатель на файл fp1 указывает на файл data1.txt. Перед fp1 явно отделяется от файлового потока data1.txt, он используется для доступа к другому файлу data2.txt.
FILE УказательОдной из возможных коррекций является явная диссоциация fp1 из файлового потока data1.txt.
#include <stdio.h>
void func1( void ) {
FILE *fp1;
fp1 = fopen ( "data1.txt", "w" );
fprintf ( fp1, "*" );
fclose(fp1);
fp1 = fopen ( "data2.txt", "w" );
fprintf ( fp1, "!" );
fclose ( fp1 );
}
Утечка памяти для конкретного потока происходит, когда вы не освобождаете динамически выделенную память для конкретного потока до конца потока.
Чтобы создать специфичное для потока хранилище, вы обычно делаете следующие шаги:
Вы создаете ключ для специфичного для потока хранилища.
Вы создаете потоки.
В каждом потоке вы динамически выделяете устройство хранения данных, а затем связываете ключ с этим устройством хранения.
После ассоциации можно считать сохраненные данные позже с помощью ключа.
Перед завершением потока вы освобождаете определенную для потока память с помощью ключа.
Шашка помечает пути выполнения в потоке, где отсутствует последний шаг.
Шашка работает с этими семействами функций:
tss_get и tss_set (C11)
pthread_getspecific и pthread_setspecific (POSIX)
Данные, хранящиеся в памяти, доступны другим процессам даже после окончания потоков (утечка памяти). Помимо уязвимостей безопасности, утечки памяти могут уменьшить объем доступной памяти и снизить эффективность.
Освободите динамически выделенную память перед концом потока.
Вы можете явно освободить динамически выделенную память с такими функциями, как free.
Кроме того, когда вы создаете ключ, можно связать функцию деструктора с клавишей. Функция деструктора вызывается со значением ключа в качестве аргумента в конце потока. В теле функции деструктора можно освободить любую память, связанную с клавишей. Если вы используете этот метод, Bug Finder все еще помечает дефект. Игнорируйте этот дефект с соответствующими комментариями. Смотрите Адрес Результаты Polyspace через исправления ошибок или обоснования.
#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 вызывает две функции:
add_data: Эта функция динамически выделяет хранилище и связывает хранилище с ключом с помощью tss_set функция.
print_data: Эта функция считывает сохраненные данные с помощью tss_get функция.
В точках, где func возвращает, динамически выделенное хранилище не освобождено.
Одной из возможных коррекций является явное освобождение динамически выделенной памяти перед оставлением начальной функции потока. См. выделенное изменение в исправленной версии.
В этой исправленной версии дефект все еще появляется на return оператор в разделе обработки ошибок func. Дефект не может возникнуть на практике, потому что раздел обработки ошибок вводится только в случае сбоя динамического выделения памяти. Проигнорируйте этот оставшийся дефект с соответствующими комментариями. Смотрите Адрес Результаты Polyspace через исправления ошибок или обоснования.
#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;
}| Решимость: Undecidable |
[1] Выдержки из стандарта «Техническая спецификация ISO/IEC TS 17961 - 2013-11-15» воспроизводятся с согласия АФНОР. Только оригинальный и полный текст стандарта, опубликованный AFNOR Editions - доступный через веб-сайт www.boutique.afnor.org - имеет нормативное значение.
1. Если смысл перевода понятен, то лучше оставьте как есть и не придирайтесь к словам, синонимам и тому подобному. О вкусах не спорим.
2. Не дополняйте перевод комментариями “от себя”. В исправлении не должно появляться дополнительных смыслов и комментариев, отсутствующих в оригинале. Такие правки не получится интегрировать в алгоритме автоматического перевода.
3. Сохраняйте структуру оригинального текста - например, не разбивайте одно предложение на два.
4. Не имеет смысла однотипное исправление перевода какого-то термина во всех предложениях. Исправляйте только в одном месте. Когда Вашу правку одобрят, это исправление будет алгоритмически распространено и на другие части документации.
5. По иным вопросам, например если надо исправить заблокированное для перевода слово, обратитесь к редакторам через форму технической поддержки.