3

私はスプリントの使い方を学びながら、C を再学習しようとしています。 安全第一!

その中にファイルポインターを持つ構造があります。ファイル ポインタは、コンストラクタ関数内で開かれ、デストラクタ関数内で閉じられます。構造体型定義で注釈が付けられて/@only@/おり、splint は、構造体内のファイル ポインターがそのメモリへの唯一のポインター (以下の詳細を参照) であることを認識しているようです。

デストラクタ関数では、ファイル ポインタが null でない限り、ファイルは閉じられます。

ただし、 splint は、 filepointer である限りファイルが閉じられているにもかかわらず、ファイル ポインターが解放されず、メモリ リークが発生していると不平を言っているようです!= NULL

コードは次のとおりです。

#include <stdio.h>

struct FileStructure {
  /*@only@*/ FILE *file;
};

static /*@noreturn@*/ void die(const char *message)
{
  if ((bool) errno) {
    perror(message);
  } else {
    printf("ERROR: %s\n",message);
  }
  exit(EXIT_FAILURE);

}

static struct FileStructure *File_open(const char *filename)
{
  struct FileStructure *filestruct = malloc(sizeof(struct FileStructure));
  if(filestruct == NULL) die("Memory error");
  filestruct->file = fopen(filename,"r+");

  if(!filestruct->file) die("Failed to open the file");
  return filestruct;
}

static void File_close(/*@only@*/ struct FileStructure *filestruct)
{
  if(filestruct) {
    if(filestruct->file != NULL ) (void) fclose(filestruct->file);
    free(filestruct);
  }
}

int main(int argc, char *argv[])
{
  struct FileStructure *filestruct;
  char *filename;

  if(argc < 1) die("USAGE: program <filename>");

  filename=argv[1];
  filestruct=File_open(filename);
  File_close(filestruct);
  return 0;

}

そして、それは次のエラーを引き起こします:

so-splint-fclose.c: (in function File_open)
so-splint-fclose.c:22:3: Dependent storage assigned to only:
                            filestruct->file = fopen(filename, "r+")
  Dependent storage is transferred to a non-dependent reference. (Use
  -dependenttrans to inhibit warning)
so-splint-fclose.c: (in function File_close)
so-splint-fclose.c:32:10: Only storage filestruct->file (type FILE *) derived
    from released storage is not released (memory leak): filestruct
  A storage leak due to incomplete deallocation of a structure or deep pointer
  is suspected. Unshared storage that is reachable from a reference that is
  being deallocated has not yet been deallocated. Splint assumes when an object
  is passed as an out only void pointer that the outer object will be
  deallocated, but the inner objects will not. (Use -compdestroy to inhibit
  warning)

2 番目のエラー:なぜ splintは が経由されているのにfilestruct->fileが閉じられていないと考えるのですか?File_closefclose

4

1 に答える 1

1

警告の防止

まず、注釈の代わりにfile使用する宣言を変更することで、両方の警告を回避できます。/*@dependent@*//*@only@*/

struct FileStructure {
  /*@dependent@*/ FILE *file;
};

これによりエラーが防止される理由

dependentストレージへのストレージの割り当てに関する最初のエラーに関しては、で使用される注釈付き関数の宣言に注釈が含まれているonlyため、これが発生します。これは、内で定義されている注釈とは対照的です。fopensplint/*@dependent@*//*@only@*fileFileStructure

# From splint's lib/standard.h
/*@null@*/ /*@dependent@*/ FILE *fopen (char *filename, char *mode) 

つまり、splint は、dependentから出力されたファイル ポインタが変数fopenに割り当てられていると不平を言っています。only

この問題を修正すると、スプリントのマニュアルfile で指定されているように、内部オブジェクトからメモリを解放しないという 2 番目のエラーも解決されます。

依存参照の有効期間が、対応する所有参照の有効期間内に含まれるようにするのは、プログラマ次第です。」 (セクション 5.2.3)

スプリントが未解放のストレージがあると考える理由

free()実際の質問については、なぜ splint が解放されていないストレージがあると考えるのか、答えは splintによって使用されるの注釈付き宣言を考慮した場合の splint からの出力にあります。

Splint は、オブジェクトが out only void ポインタとして渡された場合、外側のオブジェクトは割り当て解除されると想定しますが、内側のオブジェクトはそうではありません。

「out only void ポインター」はfree()、スプリントで使用される注釈付き関数を参照しています。

# From splint's lib/standard.h
void free( /*@null@*/ /*@out@*/ /*@only@*/ void *p ) /*@modified p@*/;

つまりfilestruct、 への入力時に「アウトのみの void ポインター」として扱われるfreeため、その内部オブジェクトは解放されないままと見なされます。

内部オブジェクトが呼び出される数行前に解放されたことを splint が認識していないことに驚いていますが、おそらくこれはすべて、内部オブジェクトに注釈を使用するfree()ように指示する splint の方法にすぎません。dependentowned

参考文献:

于 2015-08-15T11:51:26.147 に答える