aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@member.fsf.org>2015-12-20 17:35:04 +0100
committerMattias Andrée <maandree@member.fsf.org>2015-12-20 17:35:04 +0100
commit0d4b2f2670b9d90c694a8d5340611481066ea5e6 (patch)
tree347089cafd293e525f910c775bcb6af9cfa6c241
parentm (diff)
downloadslibc-0d4b2f2670b9d90c694a8d5340611481066ea5e6.tar.gz
slibc-0d4b2f2670b9d90c694a8d5340611481066ea5e6.tar.bz2
slibc-0d4b2f2670b9d90c694a8d5340611481066ea5e6.tar.xz
add needstack
Signed-off-by: Mattias Andrée <maandree@member.fsf.org>
Diffstat (limited to '')
-rw-r--r--Makefile2
-rw-r--r--include/alloca.h44
-rw-r--r--src/alloca/needstack.c154
3 files changed, 199 insertions, 1 deletions
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 <http://www.gnu.org/licenses/>.
+ */
+#include <slibc/internals.h>
+#include <alloca.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+
+
+
+/**
+ * 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();
+}
+