summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2012-06-19 01:27:26 -0400
committerRich Felker <dalias@aerifal.cx>2012-06-19 01:27:26 -0400
commita71e0af25544fd2486e57ea51c6d05abdbf44c3e (patch)
tree434e8ae22e80ae95c2121a0c89076c7e9388b150
parentca8a4e7fbdeeb05b58ac3d456bae696623b8e312 (diff)
downloadmusl-a71e0af25544fd2486e57ea51c6d05abdbf44c3e.tar.gz
stdio: handle file position correctly at program exit
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.
-rw-r--r--src/exit/exit.c8
-rw-r--r--src/stdio/__stdio_exit.c23
-rw-r--r--src/stdio/__toread.c8
-rw-r--r--src/stdio/__towrite.c7
4 files changed, 40 insertions, 6 deletions
diff --git a/src/exit/exit.c b/src/exit/exit.c
index 03c46ca5..e4aeaf15 100644
--- a/src/exit/exit.c
+++ b/src/exit/exit.c
@@ -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
index 00000000..3f87e7ed
--- /dev/null
+++ b/src/stdio/__stdio_exit.c
@@ -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);
+}
diff --git a/src/stdio/__toread.c b/src/stdio/__toread.c
index f00cc467..c2ae80fd 100644
--- a/src/stdio/__toread.c
+++ b/src/stdio/__toread.c
@@ -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();
+}
diff --git a/src/stdio/__towrite.c b/src/stdio/__towrite.c
index 4bf96f4d..ba67e0df 100644
--- a/src/stdio/__towrite.c
+++ b/src/stdio/__towrite.c
@@ -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();
}