Проблема с getpwuid () и stat () - PullRequest
1 голос
/ 04 июля 2010

У меня есть следующий код. Это дает мне проблему со свободной памятью, но я не понял, в чем именно проблема. Кажется, что getpwuid(buf->st_uid); не ладит с readdir(dirh); или с функциями статистики. Кто-нибудь знает почему?

buf = (struct stat*) malloc(sizeof(struct stat));        
for (dirp[i] = readdir(dirh); dirp[i] != NULL; dirp[++i] = readdir(dirh)){

    ptr=(char *)malloc(sizeof(strlen(mydir)));

    ptr=strdup(mydir);
    strcat(ptr,dirp[i]->d_name);

    stat(ptr,buf);
    //modos();

    getpwuid(buf->st_uid);
    printf("\t%s\n",ptr);

    //we free the buf memory
}

free(buf);
closedir(dirh);

Ответы [ 2 ]

4 голосов
/ 04 июля 2010
ptr=(char *)malloc(sizeof(strlen(mydir)));
ptr=strdup(mydir);

выглядит проблемным в лучшем случае: -)

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

Даже если бы это не было проблемой, я никогда не видел парадигму:

sizeof(strlen(mydir))

Вы можете использовать sizeof или strlen()+1 при вызове malloc. Я думаю, что то, что у вас есть, даже если бы оно работало, просто выделило бы достаточно места для size_t, возвращаемого значения из strlen. Я могу ошибаться в этом подсчете, но я не думаю, что это актуально, так как вы все равно не используете эту память из-за утечки.

Существуют и другие проблемы, такие как:

  • getpwuid должен вернуть struct passwd *, который вы игнорируете.
  • strdup дает вам копию строки, которая точно правильного размера, а затем вы strcat к ней, почти наверняка повреждаете память.

Сейчас это не проверено, но я думаю, что это, вероятно, лучшая стартовая позиция:

struct stat buf;
struct dirent * direntp;
struct passwd * pwdp
for (direntp = readdir(dirh); direntp != NULL; direntp = readdir(dirh)) {
    // Allocate enough space for directory, separator, file and nul character.

    ptr = (char*)malloc (strlen(mydir) + 1 + strlen (direntp->d_name) + 1);

    strcpy (ptr, mydir);
    strcat (ptr,"/");
    strcat (ptr, direntp->d_name);

    stat(ptr, &buf);
    //modos();

    pwdp = getpwuid (buf.st_uid);
    printf("\t%s\n",ptr);  // prob. need something from pwdp printed here as well.

    // Don't leak.    
    free (ptr);
}

closedir(dirh);
3 голосов
/ 04 июля 2010

Вы не выделяете достаточно места для строки.

Вы делаете неортодоксальный расчет длины, который игнорирует фактическую длину mydir;затем вы делаете хорошую копию имени каталога (но теряете память, ранее выделенную);Затем вы объединяете имя в конце пробела, выделенного strdup(), что всегда плохо.Если вы пропустили sizeof(), то вы бы выделяли на один байт слишком мало для строки каталога с нулевым символом в конце.

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

Вы также попираете освобожденную память, если действительно выпускаете buf внутри цикла;Вы выделяете только один раз и освобождаетесь много раз.

Обычно вы вообще не удосужились бы выделить buf;это не такая большая структура.

У вас также нет очевидного разделителя косой черты между именем каталога и компонентом имени файла;это может не иметь значения, если вы убедитесь, что у mydir есть один в конце.


Вот простая программа, которая более или менее делает то, что необходимо.

#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <pwd.h>
#include <string.h>
#include <stdlib.h>

int main(void)
{
    static const char mydir[] = "./";
    DIR *dirh;
    size_t dlen = strlen(mydir) + 1;

    if ((dirh = opendir(mydir)) != 0)
    {
        struct dirent *dirp;
        while ((dirp = readdir(dirh)) != 0)
        {
            char *str = malloc(dlen + strlen(dirp->d_name));
            if (str != 0)
            {
                struct stat buf;
                strcpy(str, mydir);
                strcat(str, dirp->d_name);
                if (stat(str, &buf) == 0)
                {
                    struct passwd *pwd = getpwuid(buf.st_uid);
                    if (pwd != 0)
                        printf("\t%s (%s)\n", str, pwd->pw_name);
                }
                free(str);
            }
        }
        closedir(dirh);
    }
    return 0;
}

Примечание: Вычисление dlen является правильным, но только потому, что значение mydir включает косую черту.Если имя каталога не включает этот завершающий слеш, для кода потребуются изменения в расчете длины и форматировании составного имени (последовательность strcpy() strcat()).Осторожно!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...