fmemopen给出了Valgrind错误

时间:2015-03-24 10:04:29

标签: c stdio

我有以下代码:

char *filedata;
FILE *f;
filedata = malloc(3);
if (filedata == NULL)
{
    fprintf(stderr, "out of memory\n");
    exit(1);
}
memcpy(filedata, "foo", 3);
f = fmemopen(filedata, 3, "r");
if (f == NULL)
{
    fprintf(stderr, "out of memory\n");
    exit(1);
}
fclose(f);
free(filedata);

现在,当我用Valgrind执行此操作时,我收到以下错误:

==32454== Invalid read of size 1
==32454==    at 0x4006D33: __GI_strlen (mc_replace_strmem.c:284)
==32454==    by 0x855B7E: fmemopen (fmemopen.c:246)
==32454==    by 0x80485BF: main (in /home/tilli/memopen/a.out)
==32454==  Address 0x402502b is 0 bytes after a block of size 3 alloc'd
==32454==    at 0x4005BDC: malloc (vg_replace_malloc.c:195)
==32454==    by 0x8048548: main (in /home/tilli/memopen/a.out)

似乎fmemopen正在为我传递给它的参数执行strlen()。但是,手册页说明fmemopen的缓冲区参数可以是字符串或内存缓冲区(因此它不必是'\0' - 终止)。此外,它表示参数必须至少为size个字节,即它。

这里有什么问题?我只是在库函数fmemopen中发现了一个错误吗?我是否更正,在极端情况下,如果fmemopen找不到strlen终结符,而是继续读取未映射的内存,则此错误可能会导致使用'\0'的程序崩溃?

我正在运行Fedora第12版。

2 个答案:

答案 0 :(得分:2)

从手册中看,\0用作流缓冲区的EOF标记,除非模式包含b。这解释了为什么strlen()将用于定位EOF。

来自man fmemopen:

  

参数模式与fopen(3)相同。如果mode指定追加模式,则指定初始文件位置    设置为缓冲区中第一个空字节(' \ 0')的位置;否则设置初始文件位置    到缓冲区的开头。由于glibc 2.9,字母' b'可以指定为模式中的第二个字符。   这提供了"二进制"模式:写入不要隐式添加终止空字节,而fseek(3)SEEK_END是相关的   tive到缓冲区的末尾(即size参数指定的值),而不是当前字符串   长度。

然而,在同一个男人中我们可以读到:

  

在为读取而打开的流中,缓冲区中的空字节(' \ 0')不会导致读取操作返回结束          文件指示。从缓冲区读取只会在文件指针大小增加时指示文件结束          超过缓冲区开始的字节。

所以你可能发现了一个错误。

答案 1 :(得分:2)

在Ubuntu 16.04上使用gcc 5.3.1和valgrind 3.11.0,valgrind不会报告任何错误。所以看来,这个bug已经被修复了。