summaryrefslogtreecommitdiff
path: root/libmisc
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2024-12-26 20:09:17 -0700
committerLuke T. Shumaker <lukeshu@lukeshu.com>2024-12-26 20:09:17 -0700
commite7e0cff1960fca598e0ba01be2bb56b65cbb9e2b (patch)
tree1e2c607ae9980b47917effe4203b4448a1dd4c5f /libmisc
parentd0e9e9c4a178fe396f3ba255bc440a15b107a097 (diff)
parent1aecc70750ee6ce9c96ebf3e6b4a7fb322ff8ca3 (diff)
Merge branch 'lukeshu/check-build'
Diffstat (limited to 'libmisc')
-rw-r--r--libmisc/CMakeLists.txt2
-rw-r--r--libmisc/assert.c4
-rw-r--r--libmisc/include/libmisc/_intercept.h21
-rw-r--r--libmisc/include/libmisc/assert.h2
-rw-r--r--libmisc/include/libmisc/log.h9
-rw-r--r--libmisc/intercept.c25
-rw-r--r--libmisc/log.c10
-rw-r--r--libmisc/tests/test_assert.c20
-rw-r--r--libmisc/tests/test_assert_min.c17
-rw-r--r--libmisc/tests/test_log.c49
-rw-r--r--libmisc/tests/test_rand.c25
11 files changed, 126 insertions, 58 deletions
diff --git a/libmisc/CMakeLists.txt b/libmisc/CMakeLists.txt
index 83e91fe..8d842c3 100644
--- a/libmisc/CMakeLists.txt
+++ b/libmisc/CMakeLists.txt
@@ -7,11 +7,13 @@ add_library(libmisc INTERFACE)
target_include_directories(libmisc SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_sources(libmisc INTERFACE
assert.c
+ intercept.c
log.c
)
target_compile_options(libmisc INTERFACE "$<$<COMPILE_LANGUAGE:C>:-fplan9-extensions>")
add_lib_test(libmisc test_assert)
+add_lib_test(libmisc test_assert_min)
add_lib_test(libmisc test_endian)
add_lib_test(libmisc test_hash)
add_lib_test(libmisc test_log)
diff --git a/libmisc/assert.c b/libmisc/assert.c
index 8231c85..69c0530 100644
--- a/libmisc/assert.c
+++ b/libmisc/assert.c
@@ -5,7 +5,6 @@
*/
#include <stdbool.h> /* for bool, true, false */
-#include <stdlib.h> /* for abort() */
#define LOG_NAME ASSERT
#include <libmisc/log.h> /* for errorf() */
@@ -13,7 +12,6 @@
#include <libmisc/assert.h>
#ifndef NDEBUG
-[[noreturn, gnu::weak]]
void __assert_msg_fail(const char *expr,
const char *file, unsigned int line, const char *func,
const char *msg) {
@@ -26,6 +24,6 @@ void __assert_msg_fail(const char *expr,
msg ? ": " : "", msg ?: "");
in_fail = false;
}
- abort();
+ __lm_abort();
}
#endif
diff --git a/libmisc/include/libmisc/_intercept.h b/libmisc/include/libmisc/_intercept.h
new file mode 100644
index 0000000..47e4620
--- /dev/null
+++ b/libmisc/include/libmisc/_intercept.h
@@ -0,0 +1,21 @@
+/* libmisc/_intercept.h - Interceptable ("weak") functions
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIBMISC__INTERCEPT_H_
+#define _LIBMISC__INTERCEPT_H_
+
+/* pico-sdk/newlib define these to be [[gnu:weak]] already, but
+ * depending on optimization options glibc might not, and GCC might
+ * assume it knows what they do and optimize them out. So define our
+ * own `__lm_` wrappers that GCC/glibc won't interfere with.
+ */
+
+[[format(printf, 1, 2)]]
+int __lm_printf(const char *format, ...);
+
+[[noreturn]] void __lm_abort(void);
+
+#endif /* _LIBMISC__INTERCEPT_H_ */
diff --git a/libmisc/include/libmisc/assert.h b/libmisc/include/libmisc/assert.h
index da2ba2b..8cf0735 100644
--- a/libmisc/include/libmisc/assert.h
+++ b/libmisc/include/libmisc/assert.h
@@ -17,7 +17,7 @@
#endif
#define assert_msg(expr, msg) __assert_msg(expr, #expr, msg) /* libmisc */
-#define assert(expr) __assert_msg(expr, #expr, NULL) /* C89, POSIX-2001 */
+#define assert(expr) __assert_msg(expr, #expr, 0) /* C89, POSIX-2001 */
#define assert_notreached(msg) do { __assert_msg(0, "notreached", msg); __builtin_unreachable(); } while (0) /* libmisc */
#define static_assert _Static_assert /* C11 */
diff --git a/libmisc/include/libmisc/log.h b/libmisc/include/libmisc/log.h
index 8c6d6be..121b0e1 100644
--- a/libmisc/include/libmisc/log.h
+++ b/libmisc/include/libmisc/log.h
@@ -10,6 +10,7 @@
#include <stdint.h> /* for uint8_t */
#include <libmisc/macro.h>
+#include <libmisc/_intercept.h>
#ifndef LOG_NAME
#error "each compilation unit that includes <libmisc/log.h> must define LOG_NAME"
@@ -21,12 +22,10 @@
#define _LOG_NDEBUG 0
#endif
-[[format(printf, 1, 2)]] int _log_printf(const char *format, ...);
-
-#define n_errorf(nam, fmt, ...) do { _log_printf("error: " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
-#define n_infof(nam, fmt, ...) do { _log_printf("info : " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
+#define n_errorf(nam, fmt, ...) do { __lm_printf("error: " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
+#define n_infof(nam, fmt, ...) do { __lm_printf("info : " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
#define n_debugf(nam, fmt, ...) do { if (LM_CAT3_(CONFIG_, nam, _DEBUG) && !_LOG_NDEBUG) \
- _log_printf("debug: " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
+ __lm_printf("debug: " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
#define errorf(fmt, ...) n_errorf(LOG_NAME, fmt, __VA_ARGS__)
#define infof(fmt, ...) n_infof(LOG_NAME, fmt, __VA_ARGS__)
diff --git a/libmisc/intercept.c b/libmisc/intercept.c
new file mode 100644
index 0000000..dda8c09
--- /dev/null
+++ b/libmisc/intercept.c
@@ -0,0 +1,25 @@
+/* libmisc/intercept.c - Interceptable ("weak") functions
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <stdarg.h> /* for va_list, va_start(), va_end() */
+#include <stdio.h> /* for vprintf() */
+#include <stdlib.h> /* for abort() */
+
+#include <libmisc/_intercept.h>
+
+[[gnu::weak]]
+int __lm_printf(const char *format, ...) {
+ va_list va;
+ va_start(va, format);
+ int ret = vprintf(format, va);
+ va_end(va);
+ return ret;
+}
+
+[[gnu::weak]]
+void __lm_abort(void) {
+ abort();
+}
diff --git a/libmisc/log.c b/libmisc/log.c
index 9bf5366..ff4dac6 100644
--- a/libmisc/log.c
+++ b/libmisc/log.c
@@ -7,19 +7,11 @@
#include <stdio.h> /* for vprintf() */
#include <stdarg.h> /* for va_list, va_start(), va_end() */
-#include <libmisc/assert.h>
+#include <libmisc/assert.h> /* for static_assert() */
#define LOG_NAME
#include <libmisc/log.h>
-int _log_printf(const char *format, ...) {
- va_list va;
- va_start(va, format);
- int ret = vprintf(format, va);
- va_end(va);
- return ret;
-}
-
static const char *byte_strs[] = {
"0x00",
"0x01",
diff --git a/libmisc/tests/test_assert.c b/libmisc/tests/test_assert.c
index 189f6de..3c2d6b6 100644
--- a/libmisc/tests/test_assert.c
+++ b/libmisc/tests/test_assert.c
@@ -5,12 +5,14 @@
*/
#include <setjmp.h>
+#include <stdarg.h> /* for va_list, va_start(), va_end() */
#include <stdbool.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
#include <libmisc/macro.h>
#include <libmisc/assert.h>
+#include <libmisc/_intercept.h>
#include "test.h"
@@ -28,17 +30,21 @@ jmp_buf global_env;
setjmp(global_env) == 0; \
})
-[[noreturn]] void abort(void) {
+void __lm_abort(void) {
global_failed = true;
longjmp(global_env, 1);
}
-#define __builtin_unreachable() test_assert(0)
-
-int vprintf(const char *format, va_list ap) {
- return vasprintf(&global_log, format, ap);
+int __lm_printf(const char *format, ...) {
+ va_list va;
+ va_start(va, format);
+ int ret = vasprintf(&global_log, format, va);
+ va_end(va);
+ return ret;
}
+#define __builtin_unreachable() test_assert(0)
+
/* Utilities ******************************************************************/
#define test_should_succeed(test) do { \
@@ -68,6 +74,7 @@ int vprintf(const char *format, va_list ap) {
static_assert(sizeof(char) == 1);
int main() {
+#ifndef NDEBUG
test_should_succeed(assert(true));
test_should_fail(assert(false), "error: ASSERT: "__FILE__":"LM_STR_(__LINE__)":main(): assertion \"false\" failed\n");
@@ -82,5 +89,6 @@ int main() {
free(global_log);
global_log = NULL;
}
+#endif
return 0;
}
diff --git a/libmisc/tests/test_assert_min.c b/libmisc/tests/test_assert_min.c
new file mode 100644
index 0000000..9c0394b
--- /dev/null
+++ b/libmisc/tests/test_assert_min.c
@@ -0,0 +1,17 @@
+/* libmisc/tests/test_assert_min.c - Tests for minimal <libmisc/assert.h>
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+/* Don't include *anything* else. */
+#include <libmisc/assert.h>
+
+static_assert(1 == 1);
+
+int main() {
+ assert_msg(1, "foo");
+ assert(1);
+ return 0;
+ assert_notreached("ret");
+}
diff --git a/libmisc/tests/test_log.c b/libmisc/tests/test_log.c
index 286738d..49a76ca 100644
--- a/libmisc/tests/test_log.c
+++ b/libmisc/tests/test_log.c
@@ -13,36 +13,43 @@
#define LOG_NAME FROBNICATE
#include <libmisc/log.h>
+#include <libmisc/_intercept.h>
+
#include "test.h"
/* Intercept output ***********************************************************/
static char *log_output = NULL;
-int vprintf(const char *format, va_list ap) {
- return vasprintf(&log_output, format, ap);
+int __lm_printf(const char *format, ...) {
+ va_list va;
+ va_start(va, format);
+ int ret = vasprintf(&log_output, format, va);
+ va_end(va);
+ return ret;
}
/* Actual tests ***************************************************************/
-#define should_print(_exp, cmd) do { \
- char *exp = _exp; \
- test_assert(!log_output); \
- cmd; \
- if (!exp) \
- test_assert(!log_output); \
- else \
- if (!(log_output != NULL && \
- strcmp(log_output, exp) == 0)) { \
- printf("exp = \"%s\"\n" \
- "act = \"%s\"\n", \
- exp, log_output); \
- test_assert(0); \
- } \
- if (log_output) { \
- free(log_output); \
- log_output = NULL; \
- } \
+#define should_print(_exp, cmd) do { \
+ char *exp = _exp; \
+ test_assert(!log_output); \
+ cmd; \
+ if (!exp) \
+ test_assert(!log_output); \
+ else { \
+ test_assert(log_output); \
+ if (strcmp(log_output, exp)) { \
+ printf("exp = \"%s\"\n" \
+ "act = \"%s\"\n", \
+ exp, log_output); \
+ test_assert(0); \
+ } \
+ } \
+ if (log_output) { \
+ free(log_output); \
+ log_output = NULL; \
+ } \
} while (0)
int main() {
@@ -50,6 +57,7 @@ int main() {
errorf("val=%d", 42));
should_print("info : FROBNICATE: val=0\n",
infof("val=%d", 0));
+#ifndef NDEBUG
#define CONFIG_FROBNICATE_DEBUG 1
should_print("debug: FROBNICATE: val=-2\n",
debugf("val=%d", -2));
@@ -57,5 +65,6 @@ int main() {
#define CONFIG_FROBNICATE_DEBUG 0
should_print(NULL,
debugf("val=%d", -2));
+#endif
return 0;
}
diff --git a/libmisc/tests/test_rand.c b/libmisc/tests/test_rand.c
index fff1b27..8076155 100644
--- a/libmisc/tests/test_rand.c
+++ b/libmisc/tests/test_rand.c
@@ -8,26 +8,18 @@
#include <setjmp.h>
#include <libmisc/rand.h>
+#include <libmisc/_intercept.h>
#include "test.h"
/* Intercept failures *********************************************************/
+#ifndef NDEBUG
jmp_buf *__catch;
-void __assert_msg_fail(const char *expr,
- const char *file, unsigned int line, const char *func,
- const char *msg) {
- static bool in_fail = false;
+void __lm_abort(void) {
if (__catch)
longjmp(*__catch, 1);
- if (!in_fail) {
- in_fail = true;
- printf("error: %s:%u:%s(): assertion \"%s\" failed%s%s\n",
- file, line, func,
- expr,
- msg ? ": " : "", msg);
- }
abort();
}
@@ -43,6 +35,7 @@ void __assert_msg_fail(const char *expr,
__catch = old_catch; \
} \
} while (0);
+#endif
/* Actual tests ***************************************************************/
@@ -51,20 +44,24 @@ void __assert_msg_fail(const char *expr,
static void test_n(uint64_t cnt) {
if (cnt == 0 || cnt > UINT64_C(1)<<63) {
+#ifndef NDEBUG
should_abort(rand_uint63n(cnt));
+#else
+ return;
+#endif
} else {
double sum = 0;
bool seen[MAX_SEE_ALL] = {0};
for (int i = 0; i < ROUNDS; i++) {
uint64_t val = rand_uint63n(cnt);
- sum += ((double)val)/(cnt-1);
+ sum += val;
test_assert(val < cnt);
if (cnt < MAX_SEE_ALL)
seen[val] = true;
}
if (cnt > 1) {
- test_assert(sum/ROUNDS > 0.45);
- test_assert(sum/ROUNDS < 0.55);
+ test_assert(sum/ROUNDS > 0.45*(cnt-1));
+ test_assert(sum/ROUNDS < 0.55*(cnt-1));
}
if (cnt < MAX_SEE_ALL) {
for (uint64_t i = 0; i < cnt; i++)