From 0d4b2f2670b9d90c694a8d5340611481066ea5e6 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 20 Dec 2015 17:35:04 +0100 Subject: add needstack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- Makefile | 2 +- include/alloca.h | 44 ++++++++++++++ src/alloca/needstack.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 src/alloca/needstack.c diff --git a/Makefile b/Makefile index 562d9d4..2393065 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ CCFLAGS_UNHOSTED = -nostdinc -ffreestanding # Preprocessor flags defined by slibc that are required to build the slibc. CCFLAGS_SLIBC_DEFS = -D_SLIBC_SOURCE=1 -D_GNU_SOURCE=1 -D_BSD_SOURCE=1 -D_SLIBC_SUPPRESS_WARNINGS=1 \ - -D_POSIX_C_SOURCE=999999L -D_XOPEN_SOURCE=9999 -D__BUILDING_SLIBC=1 + -D_POSIX_C_SOURCE=999999L -D_XOPEN_SOURCE=9999 -D_PLAN9_SOURCE=1 -D__BUILDING_SLIBC=1 # __BUILDING_SLIBC is used to that make all prototypes visible, that are otherwise # hidden because the library is compiled with a too old revision of C. diff --git a/include/alloca.h b/include/alloca.h index d54d18d..49d8879 100644 --- a/include/alloca.h +++ b/include/alloca.h @@ -53,6 +53,50 @@ void* alloca(size_t); #endif +#if defined(__PLAN9_SOURCE) +/** + * Check for execution stack overflow. If the stack of + * overflow, or will overflow, the program shall abort. + * + * It is possible that the process is killed by SIGSEGV + * instead of aborting. + * + * This is a Plan 9 from Bell Labs extension. + * + * @etymology I (need) addition (stack) space. + * + * @param n The number of bytes the stack will grow by. + * 0 can be used to check for a current stack + * overflow. Must be non-negative. + * + * @since Always. + */ +void (needstack)(int); +# elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define needstack(n) __needstack(n, __FILE__, __LINE__, __func__) +# else +# define needstack(n) __needstack(n, __FILE__, __LINE__, NULL) +# endif +#endif + + +/** + * This function is called if the `needstack` macro is called. + * It enhances the `needstack` function with detail on where + * the program failed. + * + * You should not use this function directly. + * + * @param n The number of bytes the stack will grow by. 0 can be used + * to check for a current stack overflow. Must be non-negative. + * @param file The filename of the source cose whence the check was made. + * @param line The line in the source code whence the check was made. + * @param func The function in the source code whence the check was made, + * `NULL` if unknown (C99 is required.) + */ +void __needstack(int, const char*, int, const char*) + + #endif #endif diff --git a/src/alloca/needstack.c b/src/alloca/needstack.c new file mode 100644 index 0000000..b75eb02 --- /dev/null +++ b/src/alloca/needstack.c @@ -0,0 +1,154 @@ +/** + * slibc — Yet another C library + * Copyright © 2015 Mattias Andrée (maandree@member.fsf.org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include + + + +/** + * Unless the stack can grow with `n` bytes + * without overflowing, the program shall + * either be killed by the kernel (SIGSEGV) + * or this function shall indicate that the + * stack cannot be grown. + * + * @param n The number of bytes the stack must be able to grow. + * @return 0 if the stack can grow, 1 otherwise. + */ +int stack_will_overflow(intptr_t n) +{ + void* prev_brk; + + /* TODO This function shall block calls to brk and sbrk. */ + + prev_brk = sbrk(n); + if (prev_brk == (void*)-1) + return 1; + if (brk(prev_brk)) + return 1; /* Should not happen. */ + + { + /* TODO This function shall block calls to signal.h functions. */ + + sigset_t old_mask; + sigset_t new_mask; + void* old_sigsegv_handler; + + old_sigsegv_handler = signal(SIGSEGV, SIG_DFL); + if (old_sigsegv_handler == SIG_ERR) + return 1; + + if (sigprocmask(SIG_UNBLOCK, &new_mask, &old_mask)) + return 1; + + (void) alloca((size_t)n); + + if (sigprocmask(SIG_SETMASK, &old_mask, NULL)) + return 1; + + if (signal(SIGSEGV, Sold_sigsegv_handler) == SIG_ERR) + return 1; + } + + return 0; +} + + +/** + * Check for execution stack overflow. If the stack of + * overflow, or will overflow, the program shall abort. + * + * It is possible that the process is killed by SIGSEGV + * instead of aborting. + * + * This is a Plan 9 from Bell Labs extension. + * + * @etymology I (need) addition (stack) space. + * + * @param n The number of bytes the stack will grow by. + * 0 can be used to check for a current stack + * overflow. Must be non-negative. + * + * @since Always. + */ +void (needstack)(int n) +{ + int tty; + + if (stack_will_overflow((intptr_t)n) == 0) + return; + + tty = isatty(STDERR_FILENO); + fprintf(stderr, + _("%(\033[00;01m%)%s%(\033[00m%): " + "%(\033[31m%)%s%(\033[00m%)" + "%(: %(\033[31m%)hinted stack growth: %i bytes%(\033[00m%)%)\n"), + tty, program_invocation_name, tty, + tty, (n ? _("imminent stack overflow detected") : _("stack overflow detected")), tty, + n != 0, tty, n, tty); + + fflush(NULL); /* Flush all streams. */ + abort(); +} + + +/** + * This function is called if the `needstack` macro is called. + * It enhances the `needstack` function with detail on where + * the program failed. + * + * You should not use this function directly. + * + * @param n The number of bytes the stack will grow by. 0 can be used + * to check for a current stack overflow. Must be non-negative. + * @param file The filename of the source cose whence the check was made. + * @param line The line in the source code whence the check was made. + * @param func The function in the source code whence the check was made, + * `NULL` if unknown (C99 is required.) + */ +void __needstack(int n, const char* file, int line, const char* func) +{ + int tty; + + if (stack_will_overflow((intptr_t)n) == 0) + return; + + tty = isatty(STDERR_FILENO); + fprintf(stderr, + _("%(\033[00;01m%)%s%(\033[00m%): " + "%(\033[31m%)%s%(\033[00m%) " + "at line %(\033[33m%)%i%(\033[00m%) " + "of file %(\033[35m%)%s%(\033[00m%)" + "%(, function %(\033[1;34m%)%s%(\033[00m%)%)" + "%(: %(\033[31m%)hinted stack growth: %i bytes%(\033[00m%)%)\n"), + tty, program_invocation_name, tty, + tty, (n ? _("imminent stack overflow detected") : _("stack overflow detected")), tty, + tty, line, tty, + tty, file, tty, + func != NULL, tty, func, tty, + n != 0, tty, n, tty); + + fflush(NULL); /* Flush all streams. */ + abort(); +} + -- cgit v1.2.3-70-g09d2