summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Kaivo <jkk@ung.org>2024-01-31 14:48:52 -0500
committerJakob Kaivo <jkk@ung.org>2024-01-31 14:48:52 -0500
commite30e935d35c5024a3d27abfda73957f28969584f (patch)
tree51c1a1888db16977ddcf59ab2330b1f333f9be45
parent78033913abfce71b1bcc075ed188c6b6ec087a13 (diff)
add dedicated undefined behavior handler, simplify most checks
-rw-r--r--mk/__undefined.d8
-rw-r--r--src/__checked_call.c4
-rw-r--r--src/__undefined.c31
-rw-r--r--src/_safety.h43
-rw-r--r--src/stdlib/__stdlib.c6
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
};
/*