stdio: handle file position correctly at program exit
authorRich Felker <dalias@aerifal.cx>
Tue, 19 Jun 2012 05:27:26 +0000 (01:27 -0400)
committerRich Felker <dalias@aerifal.cx>
Tue, 19 Jun 2012 05:27:26 +0000 (01:27 -0400)
for seekable files, posix imposed requirements on the offset of the
underlying open file description after a stream is closed. this was
correctly handled (as a side effect of the unconditional fflush call)
when streams were explicitly closed by fclose, but was not handled
correctly at program exit time, where fflush(0) was being used.

the weak symbol hackery is to pull in __stdio_exit if either of
__toread or __towrite is used, but avoid calling it twice so we don't
have to keep extra state. the new __stdio_exit is a streamlined fflush
variant that avoids performing any unnecessary operations and which
never unlocks the files or open file list, so we can be sure no other
threads write new data to a stream's buffer after it's already
flushed.

src/exit/exit.c
src/stdio/__stdio_exit.c [new file with mode: 0644]
src/stdio/__toread.c
src/stdio/__towrite.c

index 03c46ca541e6479f44bcee56fd828f347db615df..e4aeaf1589938da1f886fb740a7b46a76f94a275 100644 (file)
@@ -9,9 +9,10 @@ static void dummy()
 {
 }
 
-/* __towrite.c and atexit.c override these */
+/* __toread.c, __towrite.c, and atexit.c override these */
 weak_alias(dummy, __funcs_on_exit);
-weak_alias(dummy, __fflush_on_exit);
+weak_alias(dummy, __flush_on_exit);
+weak_alias(dummy, __seek_on_exit);
 
 void exit(int code)
 {
@@ -23,7 +24,8 @@ void exit(int code)
        __funcs_on_exit();
        if (libc.fini) libc.fini();
        if (libc.ldso_fini) libc.ldso_fini();
-       __fflush_on_exit();
+       __flush_on_exit();
+       __seek_on_exit();
 
        _Exit(code);
        for(;;);
diff --git a/src/stdio/__stdio_exit.c b/src/stdio/__stdio_exit.c
new file mode 100644 (file)
index 0000000..3f87e7e
--- /dev/null
@@ -0,0 +1,23 @@
+#include "stdio_impl.h"
+
+static FILE *const dummy_file = 0;
+weak_alias(dummy_file, __stdin_used);
+weak_alias(dummy_file, __stdout_used);
+weak_alias(dummy_file, __stderr_used);
+
+static void close_file(FILE *f)
+{
+       if (!f) return;
+       FLOCK(f);
+       if (f->wpos > f->wbase) f->write(f, 0, 0);
+       if (f->rpos < f->rend) f->seek(f, f->rpos-f->rend, SEEK_CUR);
+}
+
+void __stdio_exit(void)
+{
+       FILE *f;
+       OFLLOCK();
+       for (f=libc.ofl_head; f; f=f->next) close_file(f);
+       close_file(__stdin_used);
+       close_file(__stdout_used);
+}
index f00cc467ee9c4c371a874cb3943f23557976d0d0..c2ae80fd59d2ae631a0ad58631cf6909d9f6ab75 100644 (file)
@@ -12,3 +12,11 @@ int __toread(FILE *f)
        f->rpos = f->rend = f->buf;
        return 0;
 }
+
+static const int dummy = 0;
+weak_alias(dummy, __towrite_used);
+
+void __seek_on_exit()
+{
+       if (!__towrite_used) __stdio_exit();
+}
index 4bf96f4dfb505a9bffa2be928bab02ad62840ef1..ba67e0dfc36b9efb3212da277e96a3b05997eb8b 100644 (file)
@@ -17,8 +17,9 @@ int __towrite(FILE *f)
        return 0;
 }
 
-/* Link flush-on-exit code iff any stdio write functions are linked. */
-void __fflush_on_exit()
+const int __towrite_used = 1;
+
+void __flush_on_exit()
 {
-       fflush(0);
+       __stdio_exit();
 }