在使用fmemopen打开的FILE上使用rewind()

时间:2016-08-09 14:55:57

标签: c glibc stdio

使用glibc 2.24解决 - 请参阅下面的更新

这是一段C代码(用gcc 5.3.1编译,glibc 2.23):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

int main() {
  const char* s1="Original content of file.\n"
                 "still original content and some remaining original content.\n";
  const char* s2="overwriting data  with new content\n";
  const char* s3="appended data\n";

  const size_t bufsz=strlen(s1)+1;
  char buf[bufsz];
  FILE *f;
  int r;

  f=fmemopen(buf,bufsz,"w");
  assert(f!=NULL);

  // setbuf(f, NULL);          // variant no. 1
  // setbuffer(f, buf, bufsz); // variant no. 2

  r=fwrite(s1,strlen(s1),1,f);
  assert(r==1);

  r=fflush(f);
  assert(r==0);

  rewind(f);

  r=fwrite(s2,strlen(s2),1,f);
  assert(r==1);

  r=fwrite(s3,strlen(s3),1,f);
  assert(r==1);

  r=fclose(f);
  assert(r==0);

  printf("%s",buf);
}
  • 它做我期望的 - 输出是:

    overwriting data  with new content
    appended data
    and some remaining original content.
    
  • 现在,manpage fmemopen(3)建议禁用缓冲(取消注释变体1),或者明确地将buf设置为缓冲区(取消注释变体2)。

    然而,在这两种情况下,我都得到了结果:

    appended data
    ta  with new content
    ginal content and some remaining original content.
    

    因此,附加数据不是按照预期在第二个内容之后写入,而是覆盖了第二个内容。

  • 如果我以二进制模式打开文件(即用&#34; w&#34;模式替换&#34; wb&#34;),行为将保持不变。

  • valgrind不会报告任何错误(除了误报&#34;源和目标重叠&#34;在缓冲的情况下。后者是由于尝试将STDIO缓冲区写入内存,这确实是同一个地址。)

有什么问题?我犯了错误吗?或者这是一个GLIBC错误?

更新

8月4日,新的glibc 2.24版本发布。使用gcc 5.4.0和glibc 2.24,变体号。 1(无缓冲的文件)工作正常。变体2(自缓冲版本)给出了不同但仍然错误的结果。因此,我相信R ..是正确的,声称这是manpage fmemopen(3)中的文档错误。我会提出错误报告......

1 个答案:

答案 0 :(得分:2)

  

现在,manpage fmemopen(3)建议禁用缓冲(取消注释变量1),或者明确地将buf设置为缓冲区(取消注释变体2)。

后者绝对是未定义的行为。不要这样做。我不清楚你在Linux手册页中找到了什么文本:

  

或者,调用者可以明确地将buf设置为stdio流   缓冲区,同时使用:

通知stdio缓冲区的大小
setbuffer(stream, buf, size);

试图表达,但它是一个文档错误,应该可以删除。

对于无缓冲模式不起作用,这可能是一个glibc错误。尝试尽可能减少测试用例,针对最近的glibc进行测试,如果仍然发生,请提交glibc bugzilla的错误报告:

https://sourceware.org/bugzilla/enter_bug.cgi?product=glibc

当您想立即了解错误时,一个安全的选择就是调用fflush并检查返回值。