scc

simple C compiler
git clone git://git.2f30.org/scc
Log | Files | Refs | README | LICENSE

commit 33b9f7476c6f730def0034b2b36ad14dde30d2f2
parent 3ddba6b6ed93c63e246397e08acdc39a2e1744a9
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Tue,  7 Mar 2017 20:56:46 +0100

[libc] Fix exit() and atexit()

Functions registered with atexit() must be called
in reverse order. This implementation also protects
against calling exit() from an atexit() handler.

Diffstat:
libc/include/errno.h | 1+
libc/src/atexit.c | 18+++++++++---------
libc/src/exit.c | 14++++----------
3 files changed, 14 insertions(+), 19 deletions(-)

diff --git a/libc/include/errno.h b/libc/include/errno.h @@ -5,6 +5,7 @@ #define EDOM 1 #define EILSEQ 2 #define ERANGE 3 +#define ENOMEN 4 extern int errno; diff --git a/libc/src/atexit.c b/libc/src/atexit.c @@ -1,19 +1,19 @@ /* See LICENSE file for copyright and license details. */ #include <stdlib.h> +#include <errno.h> #undef atexit -extern void (*_atexitf[_ATEXIT_MAX])(void); +extern void (*_exitf[_ATEXIT_MAX])(void); +extern unsigned _exitn; int atexit(void (*fun)(void)) { - void (**bp)(void); - - for (bp = _atexitf; bp < &_atexitf[_ATEXIT_MAX] && *bp; ++bp) - /* nothing */; - if (bp == &_atexitf[_ATEXIT_MAX]) - return 0; - *bp = fun; - return 1; + if (_exitn == _ATEXIT_MAX) { + errno = ENOMEN; + return -1; + } + _exitf[_exitn++] = fun; + return 0; } diff --git a/libc/src/exit.c b/libc/src/exit.c @@ -3,19 +3,13 @@ #include <stdlib.h> #undef exit -void (*_atexitf[_ATEXIT_MAX])(void); +void (*_exitf[_ATEXIT_MAX])(void); +unsigned _exitn; void exit(int status) { - void (**bp)(void); - int i; - - for (i = _ATEXIT_MAX-1; i >= 0; --i) { - if (bp = _atexit[i]) { - *_atexit[i] = NULL; - (*bp)(); - } - } + while (_exitn > 0) + (*_exitf[--exitn])(); _Exit(status); }