我正在努力学习如何使用夹板同时也试图重新学习C.安全第一!
我有一个带有文件指针的结构。文件指针在构造函数中打开,并在析构函数中关闭。它在结构类型定义中用/@only@/
注释,并且splint似乎认识到结构中的文件指针是该内存的唯一指针(请参阅下面的详细信息)。
在析构函数中,只要文件指针不为null,文件就会关闭。
然而,splint似乎抱怨文件指针没有被释放,导致内存泄漏,即使文件指针只要文件指针!= 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)
第二个错误:为什么夹板认为filestruct->file
尚未在File_close
中关闭,即使它已通过fclose
?
答案 0 :(得分:1)
首先,通过更改file
使用/*@dependent@*/
而非/*@only@*/
注释的声明,可以避免这两种警告:
struct FileStructure {
/*@dependent@*/ FILE *file;
};
关于将dependent
存储分配给only
存储的第一个错误,这是因为fopen
使用的带注释的splint
函数包含/*@dependent@*/
注释在其声明中,与/*@only@*
中定义file
的{{1}}注释形成对比。
FileStructure
换句话说,splint抱怨从# From splint's lib/standard.h
/*@null@*/ /*@dependent@*/ FILE *fopen (char *filename, char *mode)
输出的dependent
文件指针被分配给fopen
变量。
修复此问题还解决了有关不从内部对象only
释放内存的第二个错误,因为,如splint manual中所述:
程序员应该确保依赖引用的生命周期包含在相应的自有引用的生命周期内。“(第5.2.3节)
至于实际问题,为什么splint认为存在未发布的存储,当考虑到夹板使用的file
的注释声明时,答案是在夹板的输出中:
Splint假设一个物体 作为外部对象将出的唯一void指针传递 取消分配,但内部对象不会。
“out only void pointer”指的是夹板使用的带注释的free()
函数:
free()
这意味着当输入# From splint's lib/standard.h
void free( /*@null@*/ /*@out@*/ /*@only@*/ void *p ) /*@modified p@*/;
时,filestruct
被视为“仅出无效指针”,因此假定其内部对象未发布。
我很惊讶夹板并没有弄清楚内部物体在调用free
之前被释放了几行,但也许这只是夹板的方式告诉我们使用free()
或者内部对象的dependent
注释。
参考文献:
有关注释owned
和fopen
here的更多详细信息。
splint manual(在archive.org上因为splint website在撰写本文时失败了)请参阅第5.2.3节:自有和从属参考。