diff options
author | Jakob Kaivo <jkk@ung.org> | 2024-01-31 14:48:52 -0500 |
---|---|---|
committer | Jakob Kaivo <jkk@ung.org> | 2024-01-31 14:48:52 -0500 |
commit | e30e935d35c5024a3d27abfda73957f28969584f (patch) | |
tree | 51c1a1888db16977ddcf59ab2330b1f333f9be45 | |
parent | 78033913abfce71b1bcc075ed188c6b6ec087a13 (diff) |
add dedicated undefined behavior handler, simplify most checks
-rw-r--r-- | mk/__undefined.d | 8 | ||||
-rw-r--r-- | src/__checked_call.c | 4 | ||||
-rw-r--r-- | src/__undefined.c | 31 | ||||
-rw-r--r-- | src/_safety.h | 43 | ||||
-rw-r--r-- | src/stdlib/__stdlib.c | 6 |
5 files changed, 55 insertions, 37 deletions
diff --git a/mk/__undefined.d b/mk/__undefined.d new file mode 100644 index 00000000..dda5ff29 --- /dev/null +++ b/mk/__undefined.d @@ -0,0 +1,8 @@ +libc_C.0: libc.a(__undefined.o) +libc.a(__undefined.o): $(OBJDIR)/__undefined.o + @$(AR) $(ARFLAGS) $@ $(OBJDIR)/$% + +$(OBJDIR)/__undefined.o: src/__undefined.c +$(OBJDIR)/__undefined.o: + @mkdir -p $(@D) + $(CC) -c -o $@ $(CFLAGS) src/__undefined.c diff --git a/src/__checked_call.c b/src/__checked_call.c index eb07ffd4..f11c708a 100644 --- a/src/__checked_call.c +++ b/src/__checked_call.c @@ -4,7 +4,3 @@ _Thread_local #endif struct __checked_call __checked_call = { 0 }; - -#ifdef abort_handler_s -#include "stdlib/abort_handler_s.c" -#endif diff --git a/src/__undefined.c b/src/__undefined.c new file mode 100644 index 00000000..9bffff76 --- /dev/null +++ b/src/__undefined.c @@ -0,0 +1,31 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include "_safety.h" + +#if __STDC_VERSION__ < 199901L +static _Noreturn void _Exit(int); +#include "stdlib/_Exit.c" +#endif + +_Noreturn void __undefined(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "Undefined Behavior: "); + vfprintf(stderr, fmt, ap); + if (__checked_call.file) { + fprintf(stderr, " (source: %s:%ju", __checked_call.file, __checked_call.line); + if (__checked_call.func) { + fprintf(stderr, ":%s()", __checked_call.func); + } + fprintf(stderr, ")"); + } + fprintf(stderr, "\n"); + va_end(ap); + _Exit(-1); +} + +/* +STDC(0) +*/ diff --git a/src/_safety.h b/src/_safety.h index 3a1d8fd5..fada025c 100644 --- a/src/_safety.h +++ b/src/_safety.h @@ -1,15 +1,19 @@ #ifndef ___ASSERT_H__ #define ___ASSERT_H__ -#if ! (__STDC_VERSION__ >= 201112 && defined __STDC_WANT_LIB_EXT1__) -#define abort_handler_s __abort_handler_s -#endif +_Noreturn void __undefined(const char *, ...); #include <errno.h> #include <stdio.h> #include "stdlib/_stdlib.h" #include "signal/_signal.h" +#if __STDC_VERSION__ >= 199901L +#include <inttypes.h> +#else +#include "inttypes/uintmax_t.h" +#endif + #if 0 _Thread_local #endif @@ -22,19 +26,13 @@ extern struct __checked_call { #ifndef NDEBUG #define ASSERT_NONNULL(__ptr) do { \ if (!__ptr) { \ - struct __constraint_info _ci = {0}; \ - _ci.func = __func__; \ - __stdlib.constraint_handler("Undefined behavior: " \ - "Parameter " #__ptr " can not be NULL", &_ci, 0 /* was EFAULT */); \ + __undefined("In call to %s(), parameter %s cannot be NULL", __func__, #__ptr); \ } \ } while (0) #define ASSERT_NONZERO(__n) do { \ if (!__n) { \ - struct __constraint_info _ci = {0}; \ - _ci.func = __func__; \ - __stdlib.constraint_handler("Undefined behavior: " \ - "Parameter " #__n " can not be 0", &_ci, ERANGE); \ + __undefined("In call to %s(), parameter %s cannot be 0", __func__, #__n); \ } \ } while (0) @@ -42,33 +40,20 @@ extern struct __checked_call { char *__s1 = (char*)(__p1); \ char *__s2 = (char*)(__p2); \ if (((__s1 < __s2) && ((__s1 + (__l1)) >= __s2)) || ((__s1 > __s2) && ((__s2 + (__l2)) >= __s1))) { \ - struct __constraint_info _ci = {0}; \ - _ci.func = __func__; \ - __stdlib.constraint_handler("Undefined behavior: " \ - "Parameter " #__p1 " and " #__p2 " overlap", &_ci, 0); \ + __undefined("In call to %s(), parameters %s and %s overlap", __func__, #__p1, #__p2); \ } \ } while (0) #define ASSERT_REPRESENTABLE(_n, _min, _max, _type, _sentinel) do { \ if (!(((_n) == (_sentinel)) || (((_min) <= (_n)) && ((_n) <= (_max))))) { \ - struct __constraint_info _ci = {0}; \ - _ci.func = __func__; \ - _ci.value = _n; \ - __stdlib.constraint_handler("Undefined behavior: " \ - "Parameter " #_n " must be representable as a " #_type \ - " or be equal to " #_sentinel, &_ci, ERANGE); \ + __undefined("In call to %s(), parameter %s (value 0x%ju) is not representable as a %s (range [%s, %s]) or exactly %s", __func__, #_n, (uintmax_t)(_n), #_type, #_min, #_max, #_sentinel); \ } \ - } while (0) +} while (0) #define SIGNAL_SAFE(__n) do { \ if (__n == 0 && ___signal.current != 0) { \ - struct __constraint_info _ci = {0}; \ - _ci.func = __func__; \ - _ci.signal = ___signal.current; \ - ___signal.current = 0; \ - __stdlib.constraint_handler("Undefined behavior: " \ - "Standard library function called from signal handler", \ - &_ci, 0); \ + int _sig = ___signal.current; \ + __undefined("Function %s() is not safe to call from a signal handler (signal %d)", __func__, _sig); \ } \ } while (0) diff --git a/src/stdlib/__stdlib.c b/src/stdlib/__stdlib.c index d1006bec..10117f1e 100644 --- a/src/stdlib/__stdlib.c +++ b/src/stdlib/__stdlib.c @@ -1,11 +1,9 @@ #include "_stdlib.h" -#if ! (__STDC_VERSION__ >= 201112 && defined __STDC_WANT_LIB_EXT1__) -#define abort_handler_s __abort_handler_s -#endif - struct __stdlib __stdlib = { + #if __STDC_VERSION__ >= 201112 && defined __STDC_WANT_LIB_EXT1__ .constraint_handler = abort_handler_s, + #endif }; /* |