C fmemopen给出了一个Valgrind错误
我有以下代码:C fmemopen给出了一个Valgrind错误,c,stdio,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");
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的buffer参数可以是字符串或内存缓冲区,因此它不必以“\0”结尾。此外,它还表示参数长度必须至少为大小字节,实际上是这样的
这里怎么了?我刚刚在库函数fmemopen中发现了一个bug吗?如果strlen没有找到“\0”终止符,而是继续读取未映射的内存,那么在极端情况下,此错误可能会使使用fmemopen的程序崩溃,这是正确的吗
我正在运行Fedora release 12。从手册上看,似乎\0被用作流缓冲区的EOF标记,除非模式包含b。这就解释了为什么要使用strlen来定位EOF 来自man fmemopen: 参数模式与fopen3相同。如果模式指定附加模式,则初始文件位置 设置为缓冲区中第一个空字节“\0”的位置;否则,将设置初始文件位置 到缓冲区的开始。从glibc 2.9开始,字母“b”可以指定为模式中的第二个字符。 这提供了二进制模式:写入不会隐式添加终止的空字节,并且fseek3 SEEK_END是rela- 返回到缓冲区的末尾,即由size参数指定的值,而不是当前字符串 长度 然而,在同一个人身上,我们可以看到: 在为读取而打开的流中,缓冲区中的空字节“\0”不会导致读取操作返回结束- 文件的指示。当文件指针增大时,从缓冲区读取的数据将仅指示文件结束 超过缓冲区开头的字节数
因此,您可能发现了一个bug。从手册中可以看出\0被用作流缓冲区的EOF标记,除非模式包含b。这就解释了为什么要使用strlen来定位EOF 来自man fmemopen: 参数模式与fopen3相同。如果模式指定附加模式,则初始文件位置 设置为缓冲区中第一个空字节“\0”的位置;否则,将设置初始文件位置 到缓冲区的开始。从glibc 2.9开始,字母“b”可以指定为模式中的第二个字符。 这提供了二进制模式:写入不会隐式添加终止的空字节,并且fseek3 SEEK_END是rela- 返回到缓冲区的末尾,即由size参数指定的值,而不是当前字符串 长度 然而,在同一个人身上,我们可以看到: 在为读取而打开的流中,缓冲区中的空字节“\0”不会导致读取操作返回结束- 文件的指示。当文件指针增大时,从缓冲区读取的数据将仅指示文件结束 超过缓冲区开头的字节数
因此,您可能发现了一个bug。在Ubuntu 16.04上使用gcc 5.3.1和valgrind 3.11.0,valgrind不会报告任何错误。看来,这个错误已经被修复了。在Ubuntu 16.04上使用gcc 5.3.1和valgrind 3.11.0,valgrind没有报告任何错误。看来,这个bug已经被修复了。如果不使用memcpyfiledata,foo,3;您是否执行strcpyfiledata,fo?如果我做strcpyfiledata,则为fo;然后问题消失了,正如您可以从回溯中推断的那样;您是否执行strcpyfiledata,fo?如果我做strcpyfiledata,则为fo;然后问题就消失了,你可以从回溯中推断出来。在你尝试之前,这听起来是个不错的理论。我还测试了rb模式,不幸的是错误似乎没有消失。因此,如果我正确理解fmemopen手册页,如果我有一个原始内存块而不是字符串,我应该使用b。但是,问题本身并没有随着b而消失。我的手册页面也提到了Glibc2.9,所以我想这不是因为使用了太旧的glibc版本[即使文件打开读取,甚至使用二进制模式,也确实会执行strlenc->buffer。这与man规范不匹配。在您尝试之前,这听起来是一个不错的理论。我还测试了rb模式,不幸的是错误似乎没有消失。因此,如果我正确理解fmemopen手册页,我应该使用b如果我有一个原始内存块而不是字符串。但是,问题本身并没有随着b而消失。我的手册页面也提到了glibc 2.9,所以我认为这不是因为使用了太旧的glibc版本。看看我在google上找到的源代码[即使文件打开读取,甚至在二进制模式下,也确实会执行strlenc->buffer。这与man规范不匹配。