Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C fmemopen给出了一个Valgrind错误_C_Stdio - Fatal编程技术网

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规范不匹配。