struct passwd является источником утечки памяти — как правильно освободить?

#c #struct #memory-leaks

#c #struct #утечки памяти

Вопрос:

Изолировал утечку памяти из 5 блоков с помощью «struct passwd». Пробовал несколько разных бесплатных (пользовательских) вызовов безрезультатно. Как предполагается освободить эту структуру? Несколько разных вопросов SO по теме, но я нахожу мало документации о том, как следует обрабатывать эту конкретную структуру. В остальном программа работает без проблем. Спасибо.

 #include <assert.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

int main() {
    pid_t pid = getpid();
    uid_t uid = getuid();
    struct passwd *user = getpwuid(uid);
    unsigned int bufferMaxLen = strlen(".dir.")   strlen(user->pw_name)   10;
    char* dirName = malloc(bufferMaxLen * sizeof(char));
    assert(dirName != NULL);
    sprintf(dirName, "%s.dir.%d", user->pw_name, pid);

    printf("bufferMaxLen is: %dn", bufferMaxLen);
    printf("Directory name is: %sn", dirName);

    free(dirName);
    return 0;
}
  

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

1. Откуда вы знаете, что происходит утечка памяти? man getpwuid явно указывает, что » Возвращаемое значение может указывать на статическую область и может быть перезаписано последующими вызовами getpwent(3), getpwnam() или getpwuid(). (Не передавайте возвращенный указатель на free(3).) »

2. Я считаю, что точная работа getpwuid зависит от платформы.

3. valgrind <имя исполняемого файла>

4. О, и причина, по которой вы не можете освободить всю память, даже если игнорируете предупреждение, конечно, в том, что функция выделяет внутренний буфер для чтения /etc / password (и, предположительно, для взаимодействия со службами идентификации).

5. @LHMathies — лол, я только что делал аналогичный проект, и у меня снова возникла та же проблема — ты экстрасенс!

Ответ №1:

Вы можете управлять распределением памяти, предоставляя свою собственную struct password и буфер для чтения /etc/passwd в getpwuid_r .

(Это также помогает при повторном входе, поэтому функция имеет _r суффикс — версии без суффикса «разрешено» выделять один глобальный буфер).

Ответ №2:

С этим кодом это выглядит как специфичная для реализации библиотечная функция. Вполне нормально, что библиотеки выделяют память при первом вызове функции и никогда ее не освобождают: нет способа или возможности освободить ее во время обычного выполнения, и было бы совершенно бессмысленно освобождать отдельные выделения памяти при обработке выхода, когда они должны быть освобождены при выходе программы сразу после этого.

Вы можете рассматривать такого рода выделения как статические данные, за исключением того, что они являются всего лишь статическими указателями на буфер / структуру, выделяемые только при необходимости. Преимущество в том, что используется меньше памяти, если соответствующая функция никогда не вызывается. Недостатком является немного более сложный код, стоимость времени выполнения и использование памяти, если функция действительно вызывается, не говоря уже о путанице анализатора памяти, продемонстрированной вашим вопросом :-).

Такие инструменты, как Valgrind, имеют фильтры игнорирования для сокрытия такого рода «утечек».

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

1. Хороший момент, что эта утечка «нормальная», и вам следует настроить Valgrind на игнорирование ее, если вы не делаете это, чтобы доказать, что можете 🙂

2. Интересно! Такого мотива нет, просто в практике проверки на наличие утечек.