c++gccclangfflushsanitizer

fflush() on invalid FILE pointer returns 0 if compiled with sanitizer


When I read the documentation of fflush, it says that it returns 0, it it was successful and it returns EOF (EOF is on my machine -1) otherwise. (see https://man7.org/linux/man-pages/man3/fflush.3.html or https://en.cppreference.com/w/c/io/fflush)

So I created the following example:

#include<cstdio>
#include<iostream>

int main()
{
    FILE* fp = std::fopen("/tmp/test", "w+");
    std::fclose(fp);

    std::cout << std::fflush(fp) << std::endl;
    return 0;
}

If I compile it with g++ minimal.cpp or g++ -O2 -DNDEBUG minimal.cpp, it prints -1. Which is what I expected.

However, when I compile it with g++ minimal.cpp -fsanitize=address or g++ minimal.cpp -fsanitize=thread, it prints only 0.

I can reproduce the same issue with clang too.

How can this be?

I used g++-12 and clang-15 on my Debian 12 amd64 machine. It is always the same result (i.e. fflush returns 0 instead of -1).


Solution

  • According to the documentation (7.19.5.2 in the C99 standard) for fflush:

    If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.

    That implies if you call it on a file that is not open (as you are doing), you get undefined behavior.

    This comes from the C standard historically being a "de facto" standard, collecting together all the common things that different implementations did, rather than trying to "force" different implementors to implement the same thing. So there are lots of places (particularly with errors or corner cases) where different implementations historically have done different things, so the standard just says "undefined".