Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libsrc/stdio/_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ extern int _fflush(FILE *fp);

extern void _add_opened_file(FILE *fp);
extern void _remove_opened_file(FILE *fp);
extern void _flush_opened_files(void);
extern int _detect_open_flag(const char *mode);

static inline int _fputc(int c, FILE *fp) {
Expand Down
2 changes: 1 addition & 1 deletion libsrc/stdio/_fileman.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ void _remove_opened_file(FILE *fp) {
}

__attribute__((destructor))
static void flush_opened_files(void) {
void _flush_opened_files(void) {
struct FILE **files = __fileman.opened;
for (int i = 0, length = __fileman.length; i < length; ++i) {
FILE *fp = files[i];
Expand Down
17 changes: 16 additions & 1 deletion libsrc/stdio/fflush.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,20 @@
#include "./_file.h"

int fflush(FILE *fp) {
return (fp->flush)(fp);
if (fp != NULL)
return (fp->flush)(fp);

// C11 7.21.5.2p2: If stream is a null pointer, the fflush function
// performs this flushing action on all streams for which the behavior
// is defined above (i.e. all output streams).
// Note: stdin is input-only and intentionally not flushed.
int result = 0;
// Standard output streams are statically allocated and not tracked in
// __fileman, so flush them explicitly.
if ((stdout->flush)(stdout) != 0)
result = EOF;
if ((stderr->flush)(stderr) != 0)
result = EOF;
_flush_opened_files();
return result;
}
20 changes: 20 additions & 0 deletions libsrc/tests/file_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,24 @@ TEST(ungetc) {
}
}

TEST(fflush_null) {
// fflush(NULL) must flush all output streams (C11 7.21.5.2p2).
const char fn[] = "tmp_fflush_null.txt";
FILE *fp = fopen(fn, "w");
if (EXPECT_NOT_NULL(fp)) {
// No newline, so the data stays buffered until flushed.
EXPECT_EQ(5, fwrite("hello", 1, 5, fp));
EXPECT_EQ(0, fflush(NULL));
// Data must have reached the file before fclose.
struct stat st;
if (EXPECT_EQ(0, stat(fn, &st))) {
EXPECT_EQ(5, st.st_size);
}
EXPECT_EQ(0, fclose(fp));
EXPECT_EQ(0, remove(fn));
}
// No opened files: still succeeds.
EXPECT_EQ(0, fflush(NULL));
}

XTEST_MAIN();
Loading