1

循環シンボリックリンクをチェックするプログラムをCで書いています。戦略は、structfileInfoを作成することです。

typedef struct fileInfo fileInfo;

struct fileInfo {
    ino_t inode;
    dev_t devID;
};

これにより、ファイルのiノードとdevIDが保存されます。これらの構造体の配列を作成し、新しいファイルを開く前に、ファイルがすでに存在するかどうかを毎回チェックします。もしそうなら、それは循環リンクです。

void func1(...)
{

    fileInfo **fileData = malloc(sizeof(struct fileInfo*));
    int fileDataLen = 0;
    char* path = "path of file";
    /* some flags */

    func2(path, fileData, &fileDataLen);

    for (int i = 0; i < fileDataLen; i++)
        free(fileData[i]);
    free(fileData);
}

void func2(char* path, fileInfo ** fileData, int * fileDataLen)
{
    //try to open file
     struct stat buf;
     if (openFile(file, &buf, followSymLinks) == -1)
         exit(1);

     fileData = checkForLoops(fileData, fileDataLen, &buf, file);

     if (S_ISDIR(buf.st_mode)) 
     {
         char* newPath = /* modify path */
         func2(newPath,fileData, fileDataLen);
     }

    /* other stuff */

}

int openFile(char* file, struct stat * buf, fileInfo ** fileData, int * fileDataLen)
{

     if (lstat(path, buf) < 0) 
        {
            fprintf(stderr, "lstat(%s) failed\n", path);
            return -1;
        }
     return 0;
}

fileInfo** checkForLoops(fileInfo **fileData, int * fileDataLen,struct stat *buf, 
                    char* path)
{
    for (int i = 0; i < (*fileDataLen); i++)
    {
        if (fileData[i]->inode == buf->st_ino && 
            fileData[i]->devID == buf->st_dev)
            fprintf(stderr, "circular symbolic link at %s\n", path);
    }


    fileInfo *currFile = malloc(sizeof(struct fileInfo));
    memcpy(&currFile->inode, &buf->st_ino, sizeof(buf->st_ino));
    memcpy(&currFile->devID, &buf->st_dev, sizeof(buf->st_dev));

    fileData[(*fileDataLen)] = currFile;
    (*fileDataLen)++;
    fileData = realloc(fileData, ((*fileDataLen)+1) * sizeof(struct fileInfo*));

    return fileData;
}

ただし、func2()を数回呼び出した後、メモリリークが発生し、fileDataが何も指していないことに気付きました。func2()で何も解放しないので、リークがどこから来ているのかわかりません。いくつかのreallocシェナニガンがあると思いますが、その理由はわかりません。助けていただければ幸いです!

4

3 に答える 3

2

私はコードのいくつかの奇妙なことに気づいています。

まず、の関数シグネチャのopenFilereturn-typeはですがvoid、ここで戻り値を確認します。

if (openFile(file, &buf, fileData, fileDataLen) < 0)

次に、Peterも指摘しているように、電話をかけるときに十分なスペースが割り当てられていませんrealloc

fileData = realloc(fileData, (*fileDataLen) * sizeof(struct fileInfo*));

最初の反復では(*fileDataLen) == 0、インクリメント後*fileDataLen、値は、のみになります。これは、何も再割り当てされていないことを意味します(つまり、変更されていないため、すでに指して1いるメモリを単に戻しているだけです。fileData割り当てられた配列のサイズ)。したがって、次に別の再帰呼び出し中に呼び出すときは、の値をfileData[(*fileDataLen)] = currFile;にコピーしますが、そのメモリはまだ割り当てられていません。さらに、次に呼び出されると、同じ場所にメモリが再割り当てされなくなる可能性があるため、最初の配列エントリのみがコピーされた、完全に異なる場所を指します。currFilefileData[1]reallocfileData

第3に、関数内free(fileData)func1()呼び出すことにより、メモリが指している場所の値を変更し、関数を参照して元の変数の実際のメモリアドレスを渡していないため、呼び出すことができません。言い換えると、inの呼び出しがたとえば0x10000の値を返し、その割り当てられたメモリをコード内の別の場所で呼び出した場合、0x10000で割り当てられたメモリは別の場所に移動しましたが、のローカルスコープはまだ0x10000です。したがって、あなたが効果的に電話をかけるとき、それはあなたが電話をするときに起こっていることですreallocfunc2()fileDatafunc2()malloc()func1()reallocfileDatafunc1()free(0x10000)free(fileData)、アレイのメモリが0x10000で割り当てられなくなったため、エラーが発生します。配列を解放するには、へのすべての再帰呼び出しからポインタ配列への更新されたポインタを返すか、参照をfunc2()渡す必要がありfileDataます。つまり、の関数シグネチャfunc2()とを型openFile()に変更する必要があります。また、およびにfileInfo***アクセスするときは常に、追加の間接層が必要になります。次に、他の場所を呼び出すと、実際には、割り当てられたとおりの値を変更し、そのポインターを呼び出すことができます。fileDatafunc2()openFile()reallocfileDatafunc1()free()

最後に、に割り当てられたメモリのみを解放すると、実際のノード自体ではなく、ノードへのポインタの配列のみであったため、ヒープfileDataに割り当てられたすべてのノードで大きなメモリリークが発生することに注意してください。fileInfofileData

于 2011-09-09T14:05:54.863 に答える
1

あなたの問題は、あなたが以下のために十分なメモリを割り当てていないということですfileData

fileInfo * fileData = malloc(sizeof(struct fileInfo));

ここでは、使用しているように見えるインスタンスの配列ではなく、への単一のポインタに のみメモリを割り当てます。fileInfofileInfo

申し訳ありませんが、私の最初のアイデアは間違っていました...しかし、あなたの問題は、あなたが十分なメモリを割り当てていないということのようですfileData-ちょうど別の場所で:

fileData[(*fileDataLen)] = currFile; // 1
(*fileDataLen)++;
fileData = realloc(fileData, (*fileDataLen) * sizeof(struct fileInfo*)); // 2

ここでは、必要な要素より1つ少ない要素を割り当てます。fileDataLen0から始め、fileData1つの要素を含みます。最初のファイルを開いた後、1にインクリメントfileDataLenし、2ではなく1つの要素を含むように配列を再割り当てします。したがって、2番目のファイルを開くと、バッファが// 1上記でオーバーランし、一部のメモリが上書きされます。

配列をサイズに再割り当てして、これを常に不変に保つ必要がありますfileDataLen + 1

fileData = realloc(fileData, (*fileDataLen + 1) * sizeof(struct fileInfo*));
于 2011-09-09T13:32:59.063 に答える
0

func2のパス変数に対して実行している処理の種類はわかりませんが、静的文字列を変更しようとしている可能性があります。これらの種類の文字列はプライベートメモリゾーンに格納されているため、別のメモリの問題が発生します。 OSによって予約されています。

于 2011-09-09T17:39:09.207 に答える