commit 62f0e08bbf82d768a2ef87af44b67b5547558d2f
parent 8f191a4cad7365c97247c822c482e1afda3f5b33
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Wed, 25 May 2022 18:22:06 +0200
libc: Don't use atexit() to flush streams
__putc() was using atexit() to install a handler to flush
all the output streams, but this could drive to wrong behavioud
because we cannot guarantee that handlers installed before calling
__putc() are not going to buffer anything to output streams.
Diffstat:
3 files changed, 7 insertions(+), 13 deletions(-)
diff --git a/src/libc/libc.h b/src/libc/libc.h
@@ -56,3 +56,4 @@ extern struct tzone tzones[];
 
 extern void (*_exitf[])(void);
 extern unsigned _exitn;
+extern void (*_flushall)(void);
diff --git a/src/libc/stdio/__putc.c b/src/libc/stdio/__putc.c
@@ -13,8 +13,6 @@ cleanup(void)
 int
 __putc(int ch, FILE *fp)
 {
-	static int first = 1;
-
 	if (fp->flags & _IOERR)
 		return EOF;
 
@@ -29,15 +27,7 @@ __putc(int ch, FILE *fp)
 
 	if (fp->buf == NULL && _allocbuf(fp))
 		return EOF;
-
-	if (first) {
-		if (atexit(cleanup)) {
-			fp->flags |= _IOERR;
-			errno = ENOMEM;
-			return EOF;
-		}
-		first = 0;
-	}
+	_flushall = cleanup;
 
 	if (fp->flags & _IOLBF) {
 		if (fp->wp == fp->lp && _flsbuf(fp))
diff --git a/src/libc/stdlib/exit.c b/src/libc/stdlib/exit.c
@@ -1,17 +1,20 @@
 #include <stdlib.h>
 
 #include "../libc.h"
+#include "../syscall.h"
 
 #undef exit
 
 void (*_exitf[_ATEXIT_MAX])(void);
 unsigned _exitn;
+void (*_flushall)(void);
 
 void
 exit(int status)
 {
 	while (_exitn > 0)
 		(*_exitf[--_exitn])();
-
-	_Exit(status);
+	if (_flushall)
+		(*_flushall)();
+	_exit(status);
 }