Repository: tailix/libkernaux (language: python)

Issue:
Rewrite assertions (yes, again)
* May be completely disabled (causing UB).
* Always interrupt the execution (except when testing them).
* Are a private API???
* In Ruby `AssertError` should inherit `Exception`.

Related: #41 


Discussion / hints:

Fix patch:
diff --git a/.cirrus.yml b/.cirrus.yml
index dfdf0d02..bb4e4c03 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -11,7 +11,7 @@ main_freebsd_task:
     - pkg install --yes autoconf automake libtool
   main_build_script:
     - ./autogen.sh
-    - ./configure --enable-tests CFLAGS='-O3'
+    - ./configure --enable-debug --enable-tests CFLAGS='-O3'
     - make
     - sudo make install
   main_test_script:
@@ -31,7 +31,7 @@ mruby_freebsd_task:
     - unzip mruby-3.1.0.zip
   main_build_script:
     - ./autogen.sh
-    - ./configure CFLAGS='-O3'
+    - ./configure --enable-debug CFLAGS='-O3'
     - make
     - sudo make install
   mruby_test_script:
@@ -55,7 +55,7 @@ ruby_freebsd_task:
     - sudo make install
   main_build_script:
     - ./autogen.sh
-    - ./configure CFLAGS='-O3'
+    - ./configure --enable-debug CFLAGS='-O3'
     - make
     - sudo make install
   ruby_build_script:
@@ -77,7 +77,7 @@ rust_freebsd_task:
     - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
   main_build_script:
     - ./autogen.sh
-    - ./configure CFLAGS='-O3'
+    - ./configure --enable-debug CFLAGS='-O3'
     - make
     - sudo make install
   rust_test_script:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 17b2a7c8..b16150fa 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -11,6 +11,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
+        debug: ['--disable-debug', '--enable-debug']
         cc: ['gcc', 'clang', 'tcc']
         opt: ['', '-O0', '-O3']
     steps:
@@ -20,7 +21,7 @@ jobs:
       - name: autogen
         run: ./autogen.sh
       - name: configure
-        run: ./configure --enable-tests --enable-tests-python CC='${{matrix.cc}}' CFLAGS='${{matrix.opt}}'
+        run: ./configure ${{matrix.debug}} --enable-tests --enable-tests-python CC='${{matrix.cc}}' CFLAGS='${{matrix.opt}}'
       - name: make
         run: make
       - name: check
@@ -43,7 +44,7 @@ jobs:
       - name: autogen
         run: ./autogen.sh
       - name: configure
-        run: ./configure --without-${{matrix.pkg.main}} ${{matrix.pkg.other}} --enable-tests --enable-tests-python
+        run: ./configure --enable-debug --enable-tests --enable-tests-python --without-${{matrix.pkg.main}} ${{matrix.pkg.other}}
       - name: make
         run: make
       - name: check
@@ -64,7 +65,7 @@ jobs:
       - name: extract
         run: tar -xzf "libkernaux-$(cat VERSION).tar.gz"
       - name: configure
-        run: cd "libkernaux-$(cat VERSION)" && ./configure --enable-tests --enable-tests-python
+        run: cd "libkernaux-$(cat VERSION)" && ./configure --enable-debug --enable-tests --enable-tests-python
       - name: make
         run: cd "libkernaux-$(cat VERSION)" && make
       - name: check
diff --git a/.github/workflows/mruby.yml b/.github/workflows/mruby.yml
index 5cecb80e..64c44cc8 100644
--- a/.github/workflows/mruby.yml
+++ b/.github/workflows/mruby.yml
@@ -13,6 +13,7 @@ jobs:
       MRUBY_YAML_USE_SYSTEM_LIBRARY: x
     strategy:
       matrix:
+        debug: ['--disable-debug', '--enable-debug']
         packages:
           - configure: ''
           - configure: '--without-all'
@@ -29,7 +30,7 @@ jobs:
       - name: autogen
         run: ./autogen.sh
       - name: configure
-        run: ./configure ${{matrix.packages.configure}} CFLAGS='-O3'
+        run: ./configure ${{matrix.debug}} ${{matrix.packages.configure}} CFLAGS='-O3'
       - name: make
         run: make
       - name: install
diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml
index a36b9e3b..5f7ab12b 100644
--- a/.github/workflows/ruby.yml
+++ b/.github/workflows/ruby.yml
@@ -11,6 +11,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
+        debug: ['--disable-debug', '--enable-debug']
         packages:
           - configure: ''
           - configure: '--without-all'
@@ -27,7 +28,7 @@ jobs:
       - name: autogen
         run: ./autogen.sh
       - name: configure
-        run: ./configure ${{matrix.packages.configure}} CFLAGS='-O3'
+        run: ./configure ${{matrix.debug}} ${{matrix.packages.configure}} CFLAGS='-O3'
       - name: make
         run: make
       - name: install
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 56fbd2d5..3fb6f01c 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -11,6 +11,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
+        debug: ['--disable-debug', '--enable-debug']
         packages:
           - configure: ''
           - configure: '--without-all'
@@ -26,7 +27,7 @@ jobs:
       - name: autogen
         run: ./autogen.sh
       - name: configure
-        run: ./configure ${{matrix.packages.configure}} CFLAGS='-O3'
+        run: ./configure ${{matrix.debug}} ${{matrix.packages.configure}} CFLAGS='-O3'
       - name: make
         run: make
       - name: install
diff --git a/.gitignore b/.gitignore
index 65c778b1..d7fe1794 100644
--- a/.gitignore
+++ b/.gitignore
@@ -105,14 +105,12 @@
 /include/kernaux/printf.h
 /include/kernaux/version.h
 
-/examples/assert_guards
-/examples/assert_simple
+/examples/assert
 /examples/cmdline
 /examples/fprintf
 /examples/fprintf_va
 /examples/ntoa
-/examples/panic_guards
-/examples/panic_simple
+/examples/panic
 /examples/pfa
 /examples/printf_fmt
 /examples/snprintf
@@ -136,6 +134,7 @@
 /tests/test_multiboot2_info_print
 /tests/test_multiboot2_info_validation
 /tests/test_ntoa
+/tests/test_ntoa_assert
 /tests/test_pfa
 /tests/test_pfa_assert
 /tests/test_printf_fmt_gen
diff --git a/ChangeLog b/ChangeLog
index 8cfb6a3b..52b84d46 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,7 @@
 2022-06-13  Alex Kotov  <kotovalexarian@gmail.com>
 
 	* include/kernaux/version.h.in: Added
+	* include/kernaux/assert.h: Complete rewrite
 
 2022-06-12  Alex Kotov  <kotovalexarian@gmail.com>
 
diff --git a/README.md b/README.md
index ecaa5f4f..0467dcca 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,8 @@ Table of contents
 * [Overview](#libkernaux)
 * [Table of contents](#table-of-contents)
 * [API](#api)
+  * [Definitions](#definitions)
+  * [Global variables](#global-variables)
 * [Configuration](#configuration)
   * [Non-default options](#non-default-options)
   * [Default options](#default-options)
@@ -37,10 +39,8 @@ zero). Work-in-progress APIs can change at any time.
 * Runtime environment
   * [Feature macros](/include/kernaux/version.h.in) (*stable since* **?.?.?**)
   * [Assertions](/include/kernaux/assert.h) (*stable since* **0.1.0**, *non-breaking since* **?.?.?**)
-    * [Assert: simple](/examples/assert_simple.c)
-    * [Assert: guards](/examples/assert_guards.c)
-    * [Panic: simple](/examples/panic_simple.c)
-    * [Panic: guards](/examples/panic_guards.c)
+    * [Assert](/examples/assert.c)
+    * [Panic](/examples/panic.c)
   * Stack trace *(planned)*
   * [File simulator](/include/kernaux/file.h) (*work in progress*)
   * Architecture-specific code (*work in progress*)
@@ -84,6 +84,27 @@ zero). Work-in-progress APIs can change at any time.
   * [string.h](/libc/include/string.h)
   * [sys/types.h](/libc/include/sys/types.h)
 
+### Definitions
+
+Define the following C preprocessor macros before including `<kernaux.h>` and
+`<kernaux/*.h>` files. They have effect on your code, not the library code.
+
+* `KERNAUX_DEBUG` - enable assertions
+
+### Global variables
+
+```c
+// in <kernaux/assert.h>
+void (*kernaux_assert_cb)(const char *file, int line, const char *msg)
+```
+
+Assertion callback. It's better to always set it to some function which always
+interrupts the execution, even when debugging is disabled. It may for example
+call `abort()` in hosted environment, raise an exception in Ruby, panic in Rust
+or power off the machine in freestanding environment. It may also log the error
+location and message.
+
+
 
 
 Configuration
@@ -115,6 +136,7 @@ stable options.
 
 #### Features
 
+* `--(enable|disable)-debug` - debugging
 * `--(enable|disable)-float` - floating-point arithmetic
 * `--(enable|disable)-werror` - fail on warning (`CFLAGS+='-Werror'`)
 
diff --git a/configure.ac b/configure.ac
index 3a3deaf7..ffba5da3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -43,6 +43,7 @@ AC_CONFIG_FILES([
 ###############
 
 dnl Features (enabled by default)
+AC_ARG_ENABLE([debug],        AS_HELP_STRING([--disable-debug],       [disable debugging]))
 AC_ARG_ENABLE([float],        AS_HELP_STRING([--disable-float],       [disable floating-point arithmetic]))
 AC_ARG_ENABLE([werror],       AS_HELP_STRING([--disable-werror],      [disable -Werror]))
 
@@ -108,6 +109,7 @@ AS_IF([test "$with_all" = no], do_without_all)
 ##################
 
 dnl Features (enabled by default)
+AS_IF([test "$enable_debug"        = no ], [enable_debug=no],         [enable_debug=yes])
 AS_IF([test "$enable_float"        = no ], [enable_float=no],         [enable_float=yes])
 AS_IF([test "$enable_werror"       = no ], [enable_werror=no],        [enable_werror=yes])
 
@@ -165,6 +167,7 @@ AM_CONDITIONAL([ASM_RISCV64],         [test "$host_cpu" = riscv64])
 AM_CONDITIONAL([ASM_X86_64],          [test "$host_cpu" = x86_64])
 
 dnl Features (enabled by default)
+AM_CONDITIONAL([ENABLE_DEBUG],        [test "$enable_debug"        = yes])
 AM_CONDITIONAL([ENABLE_FLOAT],        [test "$enable_float"        = yes])
 AM_CONDITIONAL([ENABLE_WERROR],       [test "$enable_werror"       = yes])
 
@@ -203,6 +206,7 @@ AS_IF([test "$host_cpu" = riscv64],        [AC_DEFINE([ASM_RISCV64],         [1]
 AS_IF([test "$host_cpu" = x86_64],         [AC_DEFINE([ASM_X86_64],          [1], [architecture is x86_64])])
 
 dnl Features (enabled by default)
+AS_IF([test "$enable_debug"        = yes], [AC_DEFINE([ENABLE_DEBUG],        [1], [enabled debugging])])
 AS_IF([test "$enable_float"        = yes], [AC_DEFINE([ENABLE_FLOAT],        [1], [enabled floating-point arithmetic])])
 AS_IF([test "$enable_werror"       = yes], [AC_DEFINE([ENABLE_WERROR],       [1], [enabled -Werror])])
 
@@ -229,6 +233,9 @@ AS_IF([test "$with_units",         = yes], [AC_DEFINE([WITH_UNITS],          [1]
 dnl Packages (disabled by default)
 AS_IF([test "$with_libc"           = yes], [AC_DEFINE([WITH_LIBC],           [1], [with libc replacement])])
 
+dnl Additional
+AS_IF([test "$enable_debug"        = yes], [AC_DEFINE([KERNAUX_DEBUG],       [1], [enabled debugging])])
+
 
 
 ##########################
diff --git a/examples/Makefile.am b/examples/Makefile.am
index d77dc548..509c5b3b 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -3,21 +3,13 @@ include $(top_srcdir)/shared.am
 TESTS =
 noinst_PROGRAMS = $(TESTS)
 
-#################
-# assert_guards #
-#################
+##########
+# assert #
+##########
 
-TESTS += assert_guards
-assert_guards_LDADD = $(top_builddir)/libkernaux.la
-assert_guards_SOURCES = assert_guards.c
-
-#################
-# assert_simple #
-#################
-
-TESTS += assert_simple
-assert_simple_LDADD = $(top_builddir)/libkernaux.la
-assert_simple_SOURCES = assert_simple.c
+TESTS += assert
+assert_LDADD = $(top_builddir)/libkernaux.la
+assert_SOURCES = assert.c
 
 ###########
 # cmdline #
@@ -63,21 +55,13 @@ ntoa_LDADD = $(top_builddir)/libkernaux.la
 ntoa_SOURCES = ntoa.c
 endif
 
-################
-# panic_guards #
-################
-
-TESTS += panic_guards
-panic_guards_LDADD = $(top_builddir)/libkernaux.la
-panic_guards_SOURCES = panic_guards.c
-
-################
-# panic_simple #
-################
+#########
+# panic #
+#########
 
-TESTS += panic_simple
-panic_simple_LDADD = $(top_builddir)/libkernaux.la
-panic_simple_SOURCES = panic_simple.c
+TESTS += panic
+panic_LDADD = $(top_builddir)/libkernaux.la
+panic_SOURCES = panic.c
 
 #######
 # pfa #
diff --git a/examples/assert_simple.c b/examples/assert.c
similarity index 97%
rename from examples/assert_simple.c
rename to examples/assert.c
index eeddfaeb..285116da 100644
--- a/examples/assert_simple.c
+++ b/examples/assert.c
@@ -1,3 +1,4 @@
+#define KERNAUX_DEBUG
 #include <kernaux/assert.h>
 
 #include <assert.h>
diff --git a/examples/assert_guards.c b/examples/assert_guards.c
deleted file mode 100644
index 7c41d152..00000000
--- a/examples/assert_guards.c
+++ /dev/null
@@ -1,123 +0,0 @@
-#include <kernaux/assert.h>
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <string.h>
-
-static unsigned int count = 0;
-static const char *last_file = NULL;
-static int last_line = 0;
-static const char *last_str = NULL;
-
-static unsigned int noreturn_count = 0;
-
-static void assert_cb(
-    const char *const file,
-    const int line,
-    const char *const str
-) {
-    ++count;
-    last_file = file;
-    last_line = line;
-    last_str = str;
-}
-
-static void test_assert_return(const int value)
-{
-    KERNAUX_ASSERT_RETURN(value > 100);
-    ++noreturn_count;
-}
-
-static bool test_assert_retval(const int value)
-{
-    KERNAUX_ASSERT_RETVAL(value > 100, false);
-    ++noreturn_count;
-    return true;
-}
-
-static void test_notnull_return(const int *const value)
-{
-    KERNAUX_NOTNULL_RETURN(value);
-    ++noreturn_count;
-}
-
-static bool test_notnull_retval(const int *const value)
-{
-    KERNAUX_NOTNULL_RETVAL(value, false);
-    ++noreturn_count;
-    return true;
-}
-
-int main()
-{
-    kernaux_assert_cb = assert_cb;
-
-    int value;
-
-    test_assert_return(123);
-
-    assert(count == 0);
-    assert(last_file == NULL);
-    assert(last_line == 0);
-    assert(last_str == NULL);
-    assert(noreturn_count == 1);
-
-    assert(test_assert_retval(123));
-
-    assert(count == 0);
-    assert(last_file == NULL);
-    assert(last_line == 0);
-    assert(last_str == NULL);
-    assert(noreturn_count == 2);
-
-    test_notnull_return(&value);
-
-    assert(count == 0);
-    assert(last_file == NULL);
-    assert(last_line == 0);
-    assert(last_str == NULL);
-    assert(noreturn_count == 3);
-
-    assert(test_notnull_retval(&value));
-
-    assert(count == 0);
-    assert(last_file == NULL);
-    assert(last_line == 0);
-    assert(last_str == NULL);
-    assert(noreturn_count == 4);
-
-    test_assert_return(0);
-
-    assert(count == 1);
-    assert(strcmp(last_file, __FILE__) == 0);
-    assert(last_line == 28);
-    assert(strcmp(last_str, "value > 100") == 0);
-    assert(noreturn_count == 4);
-
-    assert(!test_assert_retval(0));
-
-    assert(count == 2);
-    assert(strcmp(last_file, __FILE__) == 0);
-    assert(last_line == 34);
-    assert(strcmp(last_str, "value > 100") == 0);
-    assert(noreturn_count == 4);
-
-    test_notnull_return(NULL);
-
-    assert(count == 3);
-    assert(strcmp(last_file, __FILE__) == 0);
-    assert(last_line == 41);
-    assert(strcmp(last_str, "value") == 0);
-    assert(noreturn_count == 4);
-
-    assert(!test_notnull_retval(NULL));
-
-    assert(count == 4);
-    assert(strcmp(last_file, __FILE__) == 0);
-    assert(last_line == 47);
-    assert(strcmp(last_str, "value") == 0);
-    assert(noreturn_count == 4);
-
-    return 0;
-}
diff --git a/examples/panic_simple.c b/examples/panic.c
similarity index 97%
rename from examples/panic_simple.c
rename to examples/panic.c
index 4d4d19ad..375e7992 100644
--- a/examples/panic_simple.c
+++ b/examples/panic.c
@@ -1,3 +1,4 @@
+#define KERNAUX_DEBUG
 #include <kernaux/assert.h>
 
 #include <assert.h>
diff --git a/examples/panic_guards.c b/examples/panic_guards.c
deleted file mode 100644
index 384a2be3..00000000
--- a/examples/panic_guards.c
+++ /dev/null
@@ -1,74 +0,0 @@
-#include <kernaux/assert.h>
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <string.h>
-
-static unsigned int count = 0;
-static const char *last_file = NULL;
-static int last_line = 0;
-static const char *last_str = NULL;
-
-static unsigned int noreturn_count = 0;
-
-static void assert_cb(
-    const char *const file,
-    const int line,
-    const char *const str
-) {
-    ++count;
-    last_file = file;
-    last_line = line;
-    last_str = str;
-}
-
-static void test_panic_return(const bool do_panic)
-{
-    if (do_panic) KERNAUX_PANIC_RETURN("foo");
-    ++noreturn_count;
-}
-
-static bool test_panic_retval(const bool do_panic)
-{
-    if (do_panic) KERNAUX_PANIC_RETVAL("bar", false);
-    ++noreturn_count;
-    return true;
-}
-
-int main()
-{
-    kernaux_assert_cb = assert_cb;
-
-    test_panic_return(false);
-
-    assert(count == 0);
-    assert(last_file == NULL);
-    assert(last_line == 0);
-    assert(last_str == NULL);
-    assert(noreturn_count == 1);
-
-    assert(test_panic_retval(false));
-
-    assert(count == 0);
-    assert(last_file == NULL);
-    assert(last_line == 0);
-    assert(last_str == NULL);
-    assert(noreturn_count == 2);
-
-    test_panic_return(true);
-
-    assert(count == 1);
-    assert(strcmp(last_file, __FILE__) == 0);
-    assert(last_line == 28);
-    assert(strcmp(last_str, "foo") == 0);
-    assert(noreturn_count == 2);
-
-    assert(!test_panic_retval(true));
-
-    assert(count == 2);
-    assert(strcmp(last_file, __FILE__) == 0);
-    assert(last_line == 34);
-    assert(strcmp(last_str, "bar") == 0);
-    assert(noreturn_count == 2);
-}
diff --git a/include/kernaux/assert.h b/include/kernaux/assert.h
index e498c220..09e01720 100644
--- a/include/kernaux/assert.h
+++ b/include/kernaux/assert.h
@@ -5,17 +5,13 @@
 extern "C" {
 #endif
 
+#ifdef KERNAUX_DEBUG
 #define KERNAUX_PANIC(msg) (kernaux_assert_do(__FILE__, __LINE__, msg))
 #define KERNAUX_ASSERT(cond) ((cond) ? (void)0 : KERNAUX_PANIC(#cond))
-
-#define KERNAUX_PANIC_RETURN(msg)         do { KERNAUX_PANIC(msg);                return;       } while (0)
-#define KERNAUX_PANIC_RETVAL(msg, val)    do { KERNAUX_PANIC(msg);                return (val); } while (0)
-
-#define KERNAUX_ASSERT_RETURN(cond)       do { KERNAUX_ASSERT(cond); if (!(cond)) return;       } while (0)
-#define KERNAUX_ASSERT_RETVAL(cond, val)  do { KERNAUX_ASSERT(cond); if (!(cond)) return (val); } while (0)
-
-#define KERNAUX_NOTNULL_RETURN(cond)      do { KERNAUX_ASSERT(cond); if (!(cond)) return;       } while (0)
-#define KERNAUX_NOTNULL_RETVAL(cond, val) do { KERNAUX_ASSERT(cond); if (!(cond)) return (val); } while (0)
+#else
+#define KERNAUX_PANIC(msg) ((void)0)
+#define KERNAUX_ASSERT(cond) ((void)0)
+#endif
 
 void kernaux_assert_do(const char *file, int line, const char *msg);
 
diff --git a/src/cmdline.c b/src/cmdline.c
index 9abf0d63..a556bc2c 100644
--- a/src/cmdline.c
+++ b/src/cmdline.c
@@ -26,12 +26,12 @@ bool kernaux_cmdline(
     const size_t argv_count_max,
     const size_t buffer_size
 ) {
-    KERNAUX_NOTNULL_RETVAL(cmdline, false);
-    KERNAUX_NOTNULL_RETVAL(error_msg, false);
-    KERNAUX_NOTNULL_RETVAL(argc, false);
-    KERNAUX_NOTNULL_RETVAL(argv, false);
-    KERNAUX_ASSERT_RETVAL(argv_count_max > 0, false);
-    KERNAUX_ASSERT_RETVAL(buffer_size > 0, false);
+    KERNAUX_ASSERT(cmdline);
+    KERNAUX_ASSERT(error_msg);
+    KERNAUX_ASSERT(argc);
+    KERNAUX_ASSERT(argv);
+    KERNAUX_ASSERT(argv_count_max > 0);
+    KERNAUX_ASSERT(buffer_size > 0);
 
     memset(error_msg, '\0', KERNAUX_CMDLINE_ERROR_MSG_SIZE_MAX);
     *argc = 0;
diff --git a/src/console.c b/src/console.c
index 53b4dfbe..df318b12 100644
--- a/src/console.c
+++ b/src/console.c
@@ -44,7 +44,7 @@ void kernaux_console_putc(const char c __attribute__((unused)))
 
 void kernaux_console_print(const char *const s)
 {
-    KERNAUX_NOTNULL_RETURN(s);
+    KERNAUX_ASSERT(s);
 
     for (const char *c = s; *c; ++c) {
         kernaux_console_putc(*c);
@@ -54,7 +54,7 @@ void kernaux_console_print(const char *const s)
 #if defined(WITH_FILE) && defined(WITH_PRINTF)
 void kernaux_console_printf(const char *format, ...)
 {
-    KERNAUX_NOTNULL_RETURN(format);
+    KERNAUX_ASSERT(format);
 
     va_list va;
     va_start(va, format);
@@ -66,7 +66,7 @@ void kernaux_console_printf(const char *format, ...)
 
 void kernaux_console_puts(const char *const s)
 {
-    KERNAUX_NOTNULL_RETURN(s);
+    KERNAUX_ASSERT(s);
 
     kernaux_console_print(s);
     kernaux_console_putc('\n');
@@ -74,7 +74,7 @@ void kernaux_console_puts(const char *const s)
 
 void kernaux_console_write(const char *const data, const size_t size)
 {
-    KERNAUX_NOTNULL_RETURN(data);
+    KERNAUX_ASSERT(data);
 
     for (size_t i = 0; i < size; i++) {
         kernaux_console_putc(data[i]);
diff --git a/src/elf.c b/src/elf.c
index 5edb5b81..95da3cbe 100644
--- a/src/elf.c
+++ b/src/elf.c
@@ -8,7 +8,7 @@
 bool KernAux_ELF_Header_is_valid(
     const struct KernAux_ELF_Header *const header
 ) {
-    KERNAUX_NOTNULL_RETVAL(header, false);
+    KERNAUX_ASSERT(header);
 
     if (!(
         header->magic_0x7f     == 0x7f &&
diff --git a/src/file.c b/src/file.c
index b20305f8..33a50c50 100644
--- a/src/file.c
+++ b/src/file.c
@@ -16,8 +16,8 @@ struct KernAux_File KernAux_File_create(const KernAux_File_Out out)
 
 void KernAux_File_init(const KernAux_File file, const KernAux_File_Out out)
 {
-    KERNAUX_NOTNULL_RETURN(file);
-    KERNAUX_NOTNULL_RETURN(out);
+    KERNAUX_ASSERT(file);
+    KERNAUX_ASSERT(out);
 
     file->out = out;
 }
diff --git a/src/mbr.c b/src/mbr.c
index 64146018..f9f3418a 100644
--- a/src/mbr.c
+++ b/src/mbr.c
@@ -10,14 +10,14 @@
 
 bool KernAux_Mbr_is_valid(const struct KernAux_Mbr *const mbr)
 {
-    KERNAUX_NOTNULL_RETVAL(mbr, false);
+    KERNAUX_ASSERT(mbr);
 
     return KernAux_Mbr_Info_is_valid(&mbr->info);
 }
 
 bool KernAux_Mbr_Info_is_valid(const struct KernAux_Mbr_Info *const mbr_info)
 {
-    KERNAUX_NOTNULL_RETVAL(mbr_info, false);
+    KERNAUX_ASSERT(mbr_info);
 
     if (mbr_info->magic != KERNAUX_MBR_MAGIC) return false;
 
@@ -32,8 +32,9 @@ bool KernAux_Mbr_Info_is_valid(const struct KernAux_Mbr_Info *const mbr_info)
 
 bool KernAux_Mbr_Entry_is_valid(const struct KernAux_Mbr_Entry *const mbr_entry)
 {
-    KERNAUX_NOTNULL_RETVAL(mbr_entry, false);
+    KERNAUX_ASSERT(mbr_entry);
 
     // TODO: implement this
+    (void)mbr_entry;
     return true;
 }
diff --git a/src/multiboot2/header_helpers.c b/src/multiboot2/header_helpers.c
index d599b85c..c19559f0 100644
--- a/src/multiboot2/header_helpers.c
+++ b/src/multiboot2/header_helpers.c
@@ -13,7 +13,7 @@ const struct KernAux_Multiboot2_HTagBase
     const struct KernAux_Multiboot2_Header *const multiboot2_header,
     const enum KernAux_Multiboot2_HTag tag_type
 ) {
-    KERNAUX_NOTNULL_RETVAL(multiboot2_header, NULL);
+    KERNAUX_ASSERT(multiboot2_header);
 
     const struct KernAux_Multiboot2_HTagBase *tag_base =
         (struct KernAux_Multiboot2_HTagBase*)
@@ -38,14 +38,14 @@ const struct KernAux_Multiboot2_HTagBase
     const enum KernAux_Multiboot2_HTag tag_type,
     const struct KernAux_Multiboot2_HTagBase *const after_tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(multiboot2_header, NULL);
-    KERNAUX_NOTNULL_RETVAL(after_tag, NULL);
+    KERNAUX_ASSERT(multiboot2_header);
+    KERNAUX_ASSERT(after_tag);
 
     const struct KernAux_Multiboot2_HTagBase *tag_base =
         (struct KernAux_Multiboot2_HTagBase*)
         KERNAUX_MULTIBOOT2_DATA(multiboot2_header);
 
-    KERNAUX_ASSERT_RETVAL(tag_base <= after_tag, NULL);
+    KERNAUX_ASSERT(tag_base <= after_tag);
 
     while (tag_base <
            (struct KernAux_Multiboot2_HTagBase*)
diff --git a/src/multiboot2/header_is_valid.c b/src/multiboot2/header_is_valid.c
index d10cb989..f192c164 100644
--- a/src/multiboot2/header_is_valid.c
+++ b/src/multiboot2/header_is_valid.c
@@ -12,7 +12,7 @@
 bool KernAux_Multiboot2_Header_is_valid(
     const struct KernAux_Multiboot2_Header *const multiboot2_header
 ) {
-    KERNAUX_NOTNULL_RETVAL(multiboot2_header, false);
+    KERNAUX_ASSERT(multiboot2_header);
 
     if (multiboot2_header->magic != KERNAUX_MULTIBOOT2_HEADER_MAGIC) {
         return false;
@@ -86,7 +86,7 @@ bool KernAux_Multiboot2_Header_is_valid(
 bool KernAux_Multiboot2_HTagBase_is_valid(
     const struct KernAux_Multiboot2_HTagBase *tag_base
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag_base, false);
+    KERNAUX_ASSERT(tag_base);
 
     switch (tag_base->type) {
     case KERNAUX_MULTIBOOT2_HTAG_NONE:
@@ -141,7 +141,7 @@ bool KernAux_Multiboot2_HTagBase_is_valid(
 bool KernAux_Multiboot2_HTag_None_is_valid(
     const struct KernAux_Multiboot2_HTag_None *tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_HTAG_NONE &&
         tag->base.size == 8
@@ -151,7 +151,7 @@ bool KernAux_Multiboot2_HTag_None_is_valid(
 bool KernAux_Multiboot2_HTag_InfoReq_is_valid(
     const struct KernAux_Multiboot2_HTag_InfoReq *tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_HTAG_INFO_REQ &&
         tag->base.size > 8 &&
@@ -162,7 +162,7 @@ bool KernAux_Multiboot2_HTag_InfoReq_is_valid(
 bool KernAux_Multiboot2_HTag_Addr_is_valid(
     const struct KernAux_Multiboot2_HTag_Addr *tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_HTAG_ADDR &&
         tag->base.size == 24
@@ -172,7 +172,7 @@ bool KernAux_Multiboot2_HTag_Addr_is_valid(
 bool KernAux_Multiboot2_HTag_EntryAddr_is_valid(
     const struct KernAux_Multiboot2_HTag_EntryAddr *tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_HTAG_ENTRY_ADDR &&
         tag->base.size == 12
@@ -182,7 +182,7 @@ bool KernAux_Multiboot2_HTag_EntryAddr_is_valid(
 bool KernAux_Multiboot2_HTag_Flags_is_valid(
     const struct KernAux_Multiboot2_HTag_Flags *tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_HTAG_FLAGS &&
         tag->base.size == 12
@@ -192,7 +192,7 @@ bool KernAux_Multiboot2_HTag_Flags_is_valid(
 bool KernAux_Multiboot2_HTag_Framebuffer_is_valid(
     const struct KernAux_Multiboot2_HTag_Framebuffer *tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_HTAG_FRAMEBUFFER &&
         tag->base.size == 20
@@ -202,7 +202,7 @@ bool KernAux_Multiboot2_HTag_Framebuffer_is_valid(
 bool KernAux_Multiboot2_HTag_ModuleAlign_is_valid(
     const struct KernAux_Multiboot2_HTag_ModuleAlign *tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_HTAG_MODULE_ALIGN &&
         tag->base.size == 8
@@ -212,7 +212,7 @@ bool KernAux_Multiboot2_HTag_ModuleAlign_is_valid(
 bool KernAux_Multiboot2_HTag_EFIBootServices_is_valid(
     const struct KernAux_Multiboot2_HTag_EFIBootServices *tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_HTAG_EFI_BOOT_SERVICES &&
         tag->base.size == 8
@@ -222,7 +222,7 @@ bool KernAux_Multiboot2_HTag_EFIBootServices_is_valid(
 bool KernAux_Multiboot2_HTag_EFII386EntryAddr_is_valid(
     const struct KernAux_Multiboot2_HTag_EFII386EntryAddr *tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_HTAG_EFI_I386_ENTRY_ADDR &&
         tag->base.size == 12
@@ -232,7 +232,7 @@ bool KernAux_Multiboot2_HTag_EFII386EntryAddr_is_valid(
 bool KernAux_Multiboot2_HTag_EFIAmd64EntryAddr_is_valid(
     const struct KernAux_Multiboot2_HTag_EFIAmd64EntryAddr *tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_HTAG_EFI_AMD64_ENTRY_ADDR &&
         tag->base.size == 12
@@ -242,7 +242,7 @@ bool KernAux_Multiboot2_HTag_EFIAmd64EntryAddr_is_valid(
 bool KernAux_Multiboot2_HTag_RelocatableHeader_is_valid(
     const struct KernAux_Multiboot2_HTag_RelocatableHeader *tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
 
     if (!(
         tag->base.type == KERNAUX_MULTIBOOT2_HTAG_RELOCATABLE_HEADER &&
diff --git a/src/multiboot2/header_print.c b/src/multiboot2/header_print.c
index ed7b68b0..63dc493c 100644
--- a/src/multiboot2/header_print.c
+++ b/src/multiboot2/header_print.c
@@ -12,8 +12,8 @@ void KernAux_Multiboot2_Header_print(
     const struct KernAux_Multiboot2_Header *const multiboot2_header,
     void (*const printf)(const char *format, ...)
 ) {
-    KERNAUX_NOTNULL_RETURN(multiboot2_header);
-    KERNAUX_NOTNULL_RETURN(printf);
+    KERNAUX_ASSERT(multiboot2_header);
+    KERNAUX_ASSERT(printf);
 
     printf("Multiboot 2 header\n");
     printf("  magic: %u\n", multiboot2_header->magic);
@@ -45,8 +45,8 @@ void KernAux_Multiboot2_HTagBase_print(
     const struct KernAux_Multiboot2_HTagBase *const tag_base,
     void (*const printf)(const char *format, ...)
 ) {
-    KERNAUX_NOTNULL_RETURN(tag_base);
-    KERNAUX_NOTNULL_RETURN(printf);
+    KERNAUX_ASSERT(tag_base);
+    KERNAUX_ASSERT(printf);
 
     if (!KernAux_Multiboot2_HTagBase_is_valid(tag_base)) return;
 
diff --git a/src/multiboot2/info_helpers.c b/src/multiboot2/info_helpers.c
index 31a54f95..a6e0b8b2 100644
--- a/src/multiboot2/info_helpers.c
+++ b/src/multiboot2/info_helpers.c
@@ -13,7 +13,7 @@ const struct KernAux_Multiboot2_ITagBase
     const struct KernAux_Multiboot2_Info *const multiboot2_info,
     const enum KernAux_Multiboot2_ITag tag_type
 ) {
-    KERNAUX_NOTNULL_RETVAL(multiboot2_info, NULL);
+    KERNAUX_ASSERT(multiboot2_info);
 
     const struct KernAux_Multiboot2_ITagBase *tag_base =
         (struct KernAux_Multiboot2_ITagBase*)
@@ -38,14 +38,14 @@ const struct KernAux_Multiboot2_ITagBase
     const enum KernAux_Multiboot2_ITag tag_type,
     const struct KernAux_Multiboot2_ITagBase *const after_tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(multiboot2_info, NULL);
-    KERNAUX_NOTNULL_RETVAL(after_tag, NULL);
+    KERNAUX_ASSERT(multiboot2_info);
+    KERNAUX_ASSERT(after_tag);
 
     const struct KernAux_Multiboot2_ITagBase *tag_base =
         (struct KernAux_Multiboot2_ITagBase*)
         KERNAUX_MULTIBOOT2_DATA(multiboot2_info);
 
-    KERNAUX_ASSERT_RETVAL(tag_base <= after_tag, NULL);
+    KERNAUX_ASSERT(tag_base <= after_tag);
 
     while (tag_base <
            (struct KernAux_Multiboot2_ITagBase*)
@@ -63,7 +63,7 @@ const struct KernAux_Multiboot2_ITagBase
 const char *KernAux_Multiboot2_Info_boot_cmd_line(
     const struct KernAux_Multiboot2_Info *const multiboot2_info
 ) {
-    KERNAUX_NOTNULL_RETVAL(multiboot2_info, NULL);
+    KERNAUX_ASSERT(multiboot2_info);
 
     const struct KernAux_Multiboot2_ITag_BootCmdLine *const tag =
         (struct KernAux_Multiboot2_ITag_BootCmdLine*)
diff --git a/src/multiboot2/info_is_valid.c b/src/multiboot2/info_is_valid.c
index 5c7ff34b..a748140b 100644
--- a/src/multiboot2/info_is_valid.c
+++ b/src/multiboot2/info_is_valid.c
@@ -12,7 +12,7 @@
 bool KernAux_Multiboot2_Info_is_valid(
     const struct KernAux_Multiboot2_Info *const multiboot2_info
 ) {
-    KERNAUX_NOTNULL_RETVAL(multiboot2_info, false);
+    KERNAUX_ASSERT(multiboot2_info);
 
     if (multiboot2_info->total_size <
         sizeof(struct KernAux_Multiboot2_Info) +
@@ -67,7 +67,7 @@ bool KernAux_Multiboot2_Info_is_valid(
 bool KernAux_Multiboot2_ITagBase_is_valid(
     const struct KernAux_Multiboot2_ITagBase *const tag_base
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag_base, false);
+    KERNAUX_ASSERT(tag_base);
 
     switch (tag_base->type) {
     case KERNAUX_MULTIBOOT2_ITAG_NONE:
@@ -167,7 +167,7 @@ bool KernAux_Multiboot2_ITagBase_is_valid(
 bool KernAux_Multiboot2_ITag_None_is_valid(
     const struct KernAux_Multiboot2_ITag_None *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_NONE &&
         tag->base.size == 8
@@ -177,7 +177,7 @@ bool KernAux_Multiboot2_ITag_None_is_valid(
 bool KernAux_Multiboot2_ITag_BootCmdLine_is_valid(
     const struct KernAux_Multiboot2_ITag_BootCmdLine *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
 
     size_t index = 1;
 
@@ -198,7 +198,7 @@ bool KernAux_Multiboot2_ITag_BootCmdLine_is_valid(
 bool KernAux_Multiboot2_ITag_BootLoaderName_is_valid(
     const struct KernAux_Multiboot2_ITag_BootLoaderName *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
 
     size_t index = 1;
 
@@ -219,7 +219,7 @@ bool KernAux_Multiboot2_ITag_BootLoaderName_is_valid(
 bool KernAux_Multiboot2_ITag_Module_is_valid(
     const struct KernAux_Multiboot2_ITag_Module *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
 
     size_t index = 1;
 
@@ -241,7 +241,7 @@ bool KernAux_Multiboot2_ITag_Module_is_valid(
 bool KernAux_Multiboot2_ITag_BasicMemoryInfo_is_valid(
     const struct KernAux_Multiboot2_ITag_BasicMemoryInfo *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_BASIC_MEMORY_INFO &&
         tag->base.size == 16
@@ -251,7 +251,7 @@ bool KernAux_Multiboot2_ITag_BasicMemoryInfo_is_valid(
 bool KernAux_Multiboot2_ITag_BIOSBootDevice_is_valid(
     const struct KernAux_Multiboot2_ITag_BIOSBootDevice *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_BIOS_BOOT_DEVICE &&
         tag->base.size == 20
@@ -261,7 +261,7 @@ bool KernAux_Multiboot2_ITag_BIOSBootDevice_is_valid(
 bool KernAux_Multiboot2_ITag_MemoryMap_is_valid(
     const struct KernAux_Multiboot2_ITag_MemoryMap *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_MEMORY_MAP &&
         tag->base.size >= 16 &&
@@ -274,7 +274,7 @@ bool KernAux_Multiboot2_ITag_MemoryMap_is_valid(
 bool KernAux_Multiboot2_ITag_VBEInfo_is_valid(
     const struct KernAux_Multiboot2_ITag_VBEInfo *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_VBE_INFO &&
         tag->base.size == 784
@@ -284,7 +284,7 @@ bool KernAux_Multiboot2_ITag_VBEInfo_is_valid(
 bool KernAux_Multiboot2_ITag_FramebufferInfo_is_valid(
     const struct KernAux_Multiboot2_ITag_FramebufferInfo *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_FRAMEBUFFER_INFO &&
         tag->base.size >= 31
@@ -294,7 +294,7 @@ bool KernAux_Multiboot2_ITag_FramebufferInfo_is_valid(
 bool KernAux_Multiboot2_ITag_ELFSymbols_is_valid(
     const struct KernAux_Multiboot2_ITag_ELFSymbols *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_ELF_SYMBOLS &&
         tag->base.size >= 16 &&
@@ -308,7 +308,7 @@ bool KernAux_Multiboot2_ITag_ELFSymbols_is_valid(
 bool KernAux_Multiboot2_ITag_APMTable_is_valid(
     const struct KernAux_Multiboot2_ITag_APMTable *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_APM_TABLE &&
         tag->base.size == 28
@@ -318,7 +318,7 @@ bool KernAux_Multiboot2_ITag_APMTable_is_valid(
 bool KernAux_Multiboot2_ITag_EFI32bitSystemTablePtr_is_valid(
     const struct KernAux_Multiboot2_ITag_EFI32bitSystemTablePtr *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_EFI_32BIT_SYSTEM_TABLE_PTR &&
         tag->base.size == 12
@@ -328,7 +328,7 @@ bool KernAux_Multiboot2_ITag_EFI32bitSystemTablePtr_is_valid(
 bool KernAux_Multiboot2_ITag_EFI64bitSystemTablePtr_is_valid(
     const struct KernAux_Multiboot2_ITag_EFI64bitSystemTablePtr *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_EFI_64BIT_SYSTEM_TABLE_PTR &&
         tag->base.size == 16
@@ -338,7 +338,7 @@ bool KernAux_Multiboot2_ITag_EFI64bitSystemTablePtr_is_valid(
 bool KernAux_Multiboot2_ITag_SMBIOSTables_is_valid(
     const struct KernAux_Multiboot2_ITag_SMBIOSTables *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_SMBIOS_TABLES &&
         tag->base.size >= 16
@@ -348,7 +348,7 @@ bool KernAux_Multiboot2_ITag_SMBIOSTables_is_valid(
 bool KernAux_Multiboot2_ITag_ACPIOldRSDP_is_valid(
     const struct KernAux_Multiboot2_ITag_ACPIOldRSDP *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_ACPI_OLD_RSDP &&
         tag->base.size >= 8
@@ -358,7 +358,7 @@ bool KernAux_Multiboot2_ITag_ACPIOldRSDP_is_valid(
 bool KernAux_Multiboot2_ITag_ACPINewRSDP_is_valid(
     const struct KernAux_Multiboot2_ITag_ACPINewRSDP *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_ACPI_NEW_RSDP &&
         tag->base.size >= 8
@@ -368,7 +368,7 @@ bool KernAux_Multiboot2_ITag_ACPINewRSDP_is_valid(
 bool KernAux_Multiboot2_ITag_NetworkingInfo_is_valid(
     const struct KernAux_Multiboot2_ITag_NetworkingInfo *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_NETWORKING_INFO &&
         tag->base.size >= 8
@@ -378,7 +378,7 @@ bool KernAux_Multiboot2_ITag_NetworkingInfo_is_valid(
 bool KernAux_Multiboot2_ITag_EFIMemoryMap_is_valid(
     const struct KernAux_Multiboot2_ITag_EFIMemoryMap *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_EFI_MEMORY_MAP &&
         tag->base.size >= 16
@@ -388,7 +388,7 @@ bool KernAux_Multiboot2_ITag_EFIMemoryMap_is_valid(
 bool KernAux_Multiboot2_ITag_EFIBootServicesNotTerminated_is_valid(
     const struct KernAux_Multiboot2_ITag_EFIBootServicesNotTerminated *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type ==
             KERNAUX_MULTIBOOT2_ITAG_EFI_BOOT_SERVICES_NOT_TERMINATED &&
@@ -399,7 +399,7 @@ bool KernAux_Multiboot2_ITag_EFIBootServicesNotTerminated_is_valid(
 bool KernAux_Multiboot2_ITag_EFI32bitImageHandlePtr_is_valid(
     const struct KernAux_Multiboot2_ITag_EFI32bitImageHandlePtr *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_EFI_32BIT_IMAGE_HANDLE_PTR &&
         tag->base.size == 12
@@ -409,7 +409,7 @@ bool KernAux_Multiboot2_ITag_EFI32bitImageHandlePtr_is_valid(
 bool KernAux_Multiboot2_ITag_EFI64bitImageHandlePtr_is_valid(
     const struct KernAux_Multiboot2_ITag_EFI64bitImageHandlePtr *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_EFI_64BIT_IMAGE_HANDLE_PTR &&
         tag->base.size == 16
@@ -419,7 +419,7 @@ bool KernAux_Multiboot2_ITag_EFI64bitImageHandlePtr_is_valid(
 bool KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr_is_valid(
     const struct KernAux_Multiboot2_ITag_ImageLoadBasePhysAddr *const tag
 ) {
-    KERNAUX_NOTNULL_RETVAL(tag, false);
+    KERNAUX_ASSERT(tag);
     return (
         tag->base.type == KERNAUX_MULTIBOOT2_ITAG_IMAGE_LOAD_BASE_PHYS_ADDR &&
         tag->base.size == 12
diff --git a/src/multiboot2/info_print.c b/src/multiboot2/info_print.c
index e1bf75ee..09c66f72 100644
--- a/src/multiboot2/info_print.c
+++ b/src/multiboot2/info_print.c
@@ -12,8 +12,8 @@ void KernAux_Multiboot2_Info_print(
     const struct KernAux_Multiboot2_Info *const multiboot2_info,
     void (*const printf)(const char *format, ...)
 ) {
-    KERNAUX_NOTNULL_RETURN(multiboot2_info);
-    KERNAUX_NOTNULL_RETURN(printf);
+    KERNAUX_ASSERT(multiboot2_info);
+    KERNAUX_ASSERT(printf);
 
     printf("Multiboot 2 info\n");
     printf("  size: %u\n", multiboot2_info->total_size);
@@ -39,8 +39,8 @@ void KernAux_Multiboot2_ITagBase_print(
     const struct KernAux_Multiboot2_ITagBase *const tag_base,
     void (*const printf)(const char *format, ...)
 ) {
-    KERNAUX_NOTNULL_RETURN(tag_base);
-    KERNAUX_NOTNULL_RETURN(printf);
+    KERNAUX_ASSERT(tag_base);
+    KERNAUX_ASSERT(printf);
 
     if (!KernAux_Multiboot2_ITagBase_is_valid(tag_base)) return;
 
@@ -226,8 +226,8 @@ void KernAux_Multiboot2_ITag_BootCmdLine_print(
     const struct KernAux_Multiboot2_ITag_BootCmdLine *const tag,
     void (*printf)(const char *format, ...)
 ) {
-    KERNAUX_NOTNULL_RETURN(tag);
-    KERNAUX_NOTNULL_RETURN(printf);
+    KERNAUX_ASSERT(tag);
+    KERNAUX_ASSERT(printf);
 
     if (!KernAux_Multiboot2_ITag_BootCmdLine_is_valid(tag)) {
         printf("  invalid!\n");
@@ -241,8 +241,8 @@ void KernAux_Multiboot2_ITag_BootLoaderName_print(
     const struct KernAux_Multiboot2_ITag_BootLoaderName *const tag,
     void (*printf)(const char *format, ...)
 ) {
-    KERNAUX_NOTNULL_RETURN(tag);
-    KERNAUX_NOTNULL_RETURN(printf);
+    KERNAUX_ASSERT(tag);
+    KERNAUX_ASSERT(printf);
 
     if (!KernAux_Multiboot2_ITag_BootLoaderName_is_valid(tag)) {
         printf("  invalid!\n");
@@ -256,8 +256,8 @@ void KernAux_Multiboot2_ITag_MemoryMap_print(
     const struct KernAux_Multiboot2_ITag_MemoryMap *const tag,
     void (*printf)(const char *format, ...)
 ) {
-    KERNAUX_NOTNULL_RETURN(tag);
-    KERNAUX_NOTNULL_RETURN(printf);
+    KERNAUX_ASSERT(tag);
+    KERNAUX_ASSERT(printf);
 
     if (!KernAux_Multiboot2_ITag_MemoryMap_is_valid(tag)) {
         printf("  invalid!\n");
@@ -290,8 +290,8 @@ void KernAux_Multiboot2_ITag_ELFSymbols_print(
     const struct KernAux_Multiboot2_ITag_ELFSymbols *const tag,
     void (*printf)(const char *format, ...)
 ) {
-    KERNAUX_NOTNULL_RETURN(tag);
-    KERNAUX_NOTNULL_RETURN(printf);
+    KERNAUX_ASSERT(tag);
+    KERNAUX_ASSERT(printf);
 
     if (!KernAux_Multiboot2_ITag_ELFSymbols_is_valid(tag)) {
         printf("  invalid!\n");
diff --git a/src/ntoa.c b/src/ntoa.c
index 834d0111..7c8ae1d5 100644
--- a/src/ntoa.c
+++ b/src/ntoa.c
@@ -9,7 +9,7 @@
 
 char *kernaux_utoa(uint64_t value, char *buffer, int base, const char *prefix)
 {
-    KERNAUX_NOTNULL_RETVAL(buffer, NULL);
+    KERNAUX_ASSERT(buffer);
 
     // Protect caller from invalid state in case of future assertions
     *buffer = '\0';
@@ -29,7 +29,7 @@ char *kernaux_utoa(uint64_t value, char *buffer, int base, const char *prefix)
         base = -base;
     }
 
-    KERNAUX_ASSERT_RETVAL(base >= 2 && base <= 36, NULL);
+    KERNAUX_ASSERT(base >= 2 && base <= 36);
 
     // Write prefix
     if (prefix) {
@@ -37,7 +37,7 @@ char *kernaux_utoa(uint64_t value, char *buffer, int base, const char *prefix)
             if (prefix_len > KERNAUX_NTOA_MAX_PREFIX_LEN) {
                 // Protect caller from invalid state
                 *buffer = '\0';
-                KERNAUX_PANIC_RETVAL("prefix is too long", NULL);
+                KERNAUX_PANIC("prefix is too long");
             }
             *(buffer++) = *(prefix++);
         }
diff --git a/src/pfa.c b/src/pfa.c
index c899a8a0..aeb83e05 100644
--- a/src/pfa.c
+++ b/src/pfa.c
@@ -40,14 +40,14 @@ static void KernAux_PFA_mark(
 
 void KernAux_PFA_initialize(const KernAux_PFA pfa)
 {
-    KERNAUX_NOTNULL_RETURN(pfa);
+    KERNAUX_ASSERT(pfa);
     memset(pfa->flags, 0, sizeof(pfa->flags));
 }
 
 bool KernAux_PFA_is_available(const KernAux_PFA pfa, const size_t page_addr)
 {
-    KERNAUX_NOTNULL_RETVAL(pfa, false);
-    KERNAUX_ASSERT_RETVAL(page_addr % KERNAUX_PFA_PAGE_SIZE == 0, false);
+    KERNAUX_ASSERT(pfa);
+    KERNAUX_ASSERT(page_addr % KERNAUX_PFA_PAGE_SIZE == 0);
 
     return GET_FLAG_FROM_ADDR(pfa, page_addr);
 }
@@ -74,8 +74,8 @@ void KernAux_PFA_mark(
     size_t start,
     size_t end
 ) {
-    KERNAUX_NOTNULL_RETURN(pfa);
-    KERNAUX_ASSERT_RETURN(start < end);
+    KERNAUX_ASSERT(pfa);
+    KERNAUX_ASSERT(start < end);
 
     const size_t start_rem = start % KERNAUX_PFA_PAGE_SIZE;
     const size_t end_rem = (end + 1) % KERNAUX_PFA_PAGE_SIZE;
@@ -102,7 +102,7 @@ void KernAux_PFA_mark(
 
 size_t KernAux_PFA_alloc_pages(const KernAux_PFA pfa, size_t mem_size)
 {
-    KERNAUX_NOTNULL_RETVAL(pfa, 0);
+    KERNAUX_ASSERT(pfa);
 
     const size_t mem_rem = mem_size % KERNAUX_PFA_PAGE_SIZE;
 
@@ -141,8 +141,8 @@ void KernAux_PFA_free_pages(
     const size_t page_addr,
     size_t mem_size
 ) {
-    KERNAUX_NOTNULL_RETURN(pfa);
-    KERNAUX_ASSERT_RETURN(page_addr % KERNAUX_PFA_PAGE_SIZE == 0);
+    KERNAUX_ASSERT(pfa);
+    KERNAUX_ASSERT(page_addr % KERNAUX_PFA_PAGE_SIZE == 0);
 
     const size_t mem_rem = mem_size % KERNAUX_PFA_PAGE_SIZE;
 
diff --git a/src/printf.c b/src/printf.c
index 69356b89..6ec96948 100644
--- a/src/printf.c
+++ b/src/printf.c
@@ -70,8 +70,8 @@ static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, d
 
 int kernaux_fprintf(const KernAux_File file, void* arg, const char* format, ...)
 {
-    KERNAUX_NOTNULL_RETVAL(file, 0);
-    KERNAUX_NOTNULL_RETVAL(format, 0);
+    KERNAUX_ASSERT(file);
+    KERNAUX_ASSERT(format);
 
     va_list va;
     va_start(va, format);
@@ -83,8 +83,8 @@ int kernaux_fprintf(const KernAux_File file, void* arg, const char* format, ...)
 
 int kernaux_vfprintf(const KernAux_File file, void* arg, const char* format, va_list va)
 {
-    KERNAUX_NOTNULL_RETVAL(file, 0);
-    KERNAUX_NOTNULL_RETVAL(format, 0);
+    KERNAUX_ASSERT(file);
+    KERNAUX_ASSERT(format);
 
     const out_fct_wrap_type out_fct_wrap = { file->out, arg };
     return _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va);
@@ -94,8 +94,8 @@ int kernaux_vfprintf(const KernAux_File file, void* arg, const char* format, va_
 
 int kernaux_snprintf(char* buffer, size_t count, const char* format, ...)
 {
-    KERNAUX_NOTNULL_RETVAL(buffer, 0);
-    KERNAUX_NOTNULL_RETVAL(format, 0);
+    KERNAUX_ASSERT(buffer);
+    KERNAUX_ASSERT(format);
 
     va_list va;
     va_start(va, format);
@@ -106,16 +106,16 @@ int kernaux_snprintf(char* buffer, size_t count, const char* format, ...)
 
 int kernaux_vsnprintf(char* buffer, size_t count, const char* format, va_list va)
 {
-    KERNAUX_NOTNULL_RETVAL(buffer, 0);
-    KERNAUX_NOTNULL_RETVAL(format, 0);
+    KERNAUX_ASSERT(buffer);
+    KERNAUX_ASSERT(format);
 
     return _vsnprintf(_out_buffer, buffer, count, format, va);
 }
 
 int kernaux_sprintf(char* buffer, const char* format, ...)
 {
-    KERNAUX_NOTNULL_RETVAL(buffer, 0);
-    KERNAUX_NOTNULL_RETVAL(format, 0);
+    KERNAUX_ASSERT(buffer);
+    KERNAUX_ASSERT(format);
 
     va_list va;
     va_start(va, format);
@@ -130,7 +130,7 @@ int kernaux_sprintf(char* buffer, const char* format, ...)
 
 int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va)
 {
-    KERNAUX_NOTNULL_RETVAL(format, 0);
+    KERNAUX_ASSERT(format);
 
     size_t idx = 0u;
 
diff --git a/src/printf_fmt.c b/src/printf_fmt.c
index c14a5ee7..3ad2870f 100644
--- a/src/printf_fmt.c
+++ b/src/printf_fmt.c
@@ -26,7 +26,7 @@ struct KernAux_PrintfFmt_Spec KernAux_PrintfFmt_Spec_create()
 
 void KernAux_PrintfFmt_Spec_init(struct KernAux_PrintfFmt_Spec *const spec)
 {
-    KERNAUX_NOTNULL_RETURN(spec);
+    KERNAUX_ASSERT(spec);
 
     spec->flags = 0u;
     spec->width = 0u;
@@ -40,8 +40,8 @@ void KernAux_PrintfFmt_Spec_init(struct KernAux_PrintfFmt_Spec *const spec)
 
 const char *KernAux_PrintfFmt_Spec_parse(struct KernAux_PrintfFmt_Spec *spec, const char *format)
 {
-    KERNAUX_NOTNULL_RETVAL(spec, NULL);
-    KERNAUX_NOTNULL_RETVAL(format, NULL);
+    KERNAUX_ASSERT(spec);
+    KERNAUX_ASSERT(format);
 
     KernAux_PrintfFmt_Spec_parse_flags(spec, &format);
     KernAux_PrintfFmt_Spec_parse_width(spec, &format);
@@ -54,9 +54,9 @@ const char *KernAux_PrintfFmt_Spec_parse(struct KernAux_PrintfFmt_Spec *spec, co
 
 void KernAux_PrintfFmt_Spec_parse_flags(struct KernAux_PrintfFmt_Spec *const spec, const char **const format)
 {
-    KERNAUX_NOTNULL_RETURN(spec);
-    KERNAUX_NOTNULL_RETURN(format);
-    KERNAUX_NOTNULL_RETURN(*format);
+    KERNAUX_ASSERT(spec);
+    KERNAUX_ASSERT(format);
+    KERNAUX_ASSERT(*format);
 
     bool running = true;
     do {
@@ -73,9 +73,9 @@ void KernAux_PrintfFmt_Spec_parse_flags(struct KernAux_PrintfFmt_Spec *const spe
 
 void KernAux_PrintfFmt_Spec_parse_width(struct KernAux_PrintfFmt_Spec *const spec, const char **const format)
 {
-    KERNAUX_NOTNULL_RETURN(spec);
-    KERNAUX_NOTNULL_RETURN(format);
-    KERNAUX_NOTNULL_RETURN(*format);
+    KERNAUX_ASSERT(spec);
+    KERNAUX_ASSERT(format);
+    KERNAUX_ASSERT(*format);
 
     if (isdigit(**format)) {
         spec->width = _atoi(format);
@@ -90,9 +90,9 @@ void KernAux_PrintfFmt_Spec_parse_width(struct KernAux_PrintfFmt_Spec *const spe
 
 void KernAux_PrintfFmt_Spec_parse_precision(struct KernAux_PrintfFmt_Spec *const spec, const char **const format)
 {
-    KERNAUX_NOTNULL_RETURN(spec);
-    KERNAUX_NOTNULL_RETURN(format);
-    KERNAUX_NOTNULL_RETURN(*format);
+    KERNAUX_ASSERT(spec);
+    KERNAUX_ASSERT(format);
+    KERNAUX_ASSERT(*format);
 
     if (**format == '.') {
         spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_PRECISION;
@@ -113,9 +113,9 @@ void KernAux_PrintfFmt_Spec_parse_precision(struct KernAux_PrintfFmt_Spec *const
 
 void KernAux_PrintfFmt_Spec_parse_length(struct KernAux_PrintfFmt_Spec *const spec, const char **const format)
 {
-    KERNAUX_NOTNULL_RETURN(spec);
-    KERNAUX_NOTNULL_RETURN(format);
-    KERNAUX_NOTNULL_RETURN(*format);
+    KERNAUX_ASSERT(spec);
+    KERNAUX_ASSERT(format);
+    KERNAUX_ASSERT(*format);
 
     switch (**format) {
         case 'l':
@@ -153,9 +153,9 @@ void KernAux_PrintfFmt_Spec_parse_length(struct KernAux_PrintfFmt_Spec *const sp
 
 void KernAux_PrintfFmt_Spec_parse_type(struct KernAux_PrintfFmt_Spec *const spec, const char **const format)
 {
-    KERNAUX_NOTNULL_RETURN(spec);
-    KERNAUX_NOTNULL_RETURN(format);
-    KERNAUX_NOTNULL_RETURN(*format);
+    KERNAUX_ASSERT(spec);
+    KERNAUX_ASSERT(format);
+    KERNAUX_ASSERT(*format);
 
     switch (**format) {
         case 'd':
@@ -249,7 +249,7 @@ void KernAux_PrintfFmt_Spec_parse_type(struct KernAux_PrintfFmt_Spec *const spec
 
 void KernAux_PrintfFmt_Spec_set_width(struct KernAux_PrintfFmt_Spec *const spec, const int width)
 {
-    KERNAUX_NOTNULL_RETURN(spec);
+    KERNAUX_ASSERT(spec);
 
     if (width < 0) {
         spec->flags |= KERNAUX_PRINTF_FMT_FLAGS_LEFT; // reverse padding
@@ -261,7 +261,7 @@ void KernAux_PrintfFmt_Spec_set_width(struct KernAux_PrintfFmt_Spec *const spec,
 
 void KernAux_PrintfFmt_Spec_set_precision(struct KernAux_PrintfFmt_Spec *const spec, const int precision)
 {
-    KERNAUX_NOTNULL_RETURN(spec);
+    KERNAUX_ASSERT(spec);
 
     spec->precision = precision > 0 ? (unsigned int)precision : 0u;
 }
diff --git a/src/units.c b/src/units.c
index cd4834f6..87f04db2 100644
--- a/src/units.c
+++ b/src/units.c
@@ -16,8 +16,8 @@ bool kernaux_units_human_raw(
     char *const buffer,
     const size_t buffer_size
 ) {
-    KERNAUX_NOTNULL_RETVAL(buffer, false);
-    KERNAUX_ASSERT_RETVAL(buffer_size > 0, false);
+    KERNAUX_ASSERT(buffer);
+    KERNAUX_ASSERT(buffer_size > 0);
 
     char tmp_buffer[TMP_BUFFER_SIZE];
     char *tmp = tmp_buffer;
@@ -56,8 +56,8 @@ bool kernaux_units_human_dec(
     char *const buffer,
     const size_t buffer_size
 ) {
-    KERNAUX_NOTNULL_RETVAL(buffer, false);
-    KERNAUX_ASSERT_RETVAL(buffer_size > 0, false);
+    KERNAUX_ASSERT(buffer);
+    KERNAUX_ASSERT(buffer_size > 0);
 
     char tmp_buffer[TMP_BUFFER_SIZE];
     char *tmp = tmp_buffer;


Test patch:
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 94c5194f..aa7228f7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -204,6 +204,18 @@ test_ntoa_LDADD = $(top_builddir)/libkernaux.la
 test_ntoa_SOURCES = test_ntoa.c
 endif
 
+####################
+# test_ntoa_assert #
+####################
+
+if ENABLE_DEBUG
+if WITH_NTOA
+TESTS += test_ntoa_assert
+test_ntoa_assert_LDADD = $(top_builddir)/libkernaux.la
+test_ntoa_assert_SOURCES = test_ntoa_assert.c
+endif
+endif
+
 ############
 # test_pfa #
 ############
@@ -218,11 +230,13 @@ endif
 # test_pfa_assert #
 ###################
 
+if ENABLE_DEBUG
 if WITH_PFA
 TESTS += test_pfa_assert
 test_pfa_assert_LDADD = $(top_builddir)/libkernaux.la
 test_pfa_assert_SOURCES = test_pfa_assert.c
 endif
+endif
 
 #######################
 # test_printf_fmt_gen #
diff --git a/tests/test_ntoa.c b/tests/test_ntoa.c
index f38ac0c7..0788a69a 100644
--- a/tests/test_ntoa.c
+++ b/tests/test_ntoa.c
@@ -2,7 +2,6 @@
 #include "config.h"
 #endif
 
-#include <kernaux/assert.h>
 #include <kernaux/ntoa.h>
 
 #include <assert.h>
@@ -513,51 +512,6 @@ static const struct {
     { INT64_MIN,                "-8000000000000000" },
 };
 
-static unsigned int assert_count_exp = 0;
-static unsigned int assert_count_ctr = 0;
-
-static const char *assert_last_file = NULL;
-static int assert_last_line = 0;
-static const char *assert_last_msg = NULL;
-
-static void assert_cb(
-    const char *const file,
-    const int line,
-    const char *const msg
-) {
-    ++assert_count_ctr;
-
-    assert_last_file = file;
-    assert_last_line = line;
-    assert_last_msg = msg;
-}
-
-static void test_utoa_assert(char *const buffer, const int base)
-{
-    assert(kernaux_utoa(0, buffer, base, NULL) == NULL);
-    assert(assert_count_ctr == ++assert_count_exp);
-    assert(strstr(assert_last_file, "src/ntoa.c") != NULL);
-    assert(assert_last_line != 0);
-    assert(assert_last_msg != NULL);
-
-    assert_last_file = NULL;
-    assert_last_line = 0;
-    assert_last_msg = NULL;
-}
-
-static void test_itoa_assert(char *const buffer, const int base)
-{
-    assert(kernaux_itoa(0, buffer, base, NULL) == NULL);
-    assert(assert_count_ctr == ++assert_count_exp);
-    assert(strstr(assert_last_file, "src/ntoa.c") != NULL);
-    assert(assert_last_line != 0);
-    assert(assert_last_msg != NULL);
-
-    assert_last_file = NULL;
-    assert_last_line = 0;
-    assert_last_msg = NULL;
-}
-
 static const char *str_end(const char *str)
 {
     for (;; ++str) if (*str == '\0') return str;
@@ -565,72 +519,6 @@ static const char *str_end(const char *str)
 
 int main()
 {
-    kernaux_assert_cb = assert_cb;
-
-    {
-        char buffer[KERNAUX_UTOA_MIN_BUFFER_SIZE + KERNAUX_NTOA_MAX_PREFIX_LEN];
-
-        const char *const end1 =
-            kernaux_utoa(123, buffer, 'd', VALID_LONG_PREFIX);
-        assert(strcmp(buffer, VALID_LONG_PREFIX"123") == 0);
-        assert(end1 == str_end(buffer));
-        assert(assert_count_ctr == assert_count_exp);
-        assert(assert_last_file == NULL);
-        assert(assert_last_line == 0);
-        assert(assert_last_msg == NULL);
-
-        const char *const end2 =
-            kernaux_utoa(123, buffer, 'd', TOO_LONG_PREFIX);
-        assert(strcmp(buffer, VALID_LONG_PREFIX) == 0);
-        assert(end2 == NULL);
-        assert(assert_count_ctr == ++assert_count_exp);
-        assert(strstr(assert_last_file, "src/ntoa.c") != NULL);
-        assert(assert_last_line != 0);
-        assert(strcmp(assert_last_msg, "prefix is too long") == 0);
-        assert_last_file = NULL;
-        assert_last_line = 0;
-        assert_last_msg = NULL;
-
-        test_utoa_assert(NULL, 'd');
-        test_utoa_assert(buffer, 0);
-        test_utoa_assert(buffer, 1);
-        test_utoa_assert(buffer, -1);
-        test_utoa_assert(buffer, 37);
-        test_utoa_assert(buffer, -37);
-    }
-
-    {
-        char buffer[KERNAUX_ITOA_MIN_BUFFER_SIZE + KERNAUX_NTOA_MAX_PREFIX_LEN];
-
-        const char *const end1 =
-            kernaux_itoa(123, buffer, 'd', VALID_LONG_PREFIX);
-        assert(strcmp(buffer, VALID_LONG_PREFIX"123") == 0);
-        assert(end1 == str_end(buffer));
-        assert(assert_count_ctr == assert_count_exp);
-        assert(assert_last_file == NULL);
-        assert(assert_last_line == 0);
-        assert(assert_last_msg == NULL);
-
-        const char *const end2 =
-            kernaux_itoa(123, buffer, 'd', TOO_LONG_PREFIX);
-        assert(strcmp(buffer, VALID_LONG_PREFIX) == 0);
-        assert(end2 == NULL);
-        assert(assert_count_ctr == ++assert_count_exp);
-        assert(strstr(assert_last_file, "src/ntoa.c") != NULL);
-        assert(assert_last_line != 0);
-        assert(strcmp(assert_last_msg, "prefix is too long") == 0);
-        assert_last_file = NULL;
-        assert_last_line = 0;
-        assert_last_msg = NULL;
-
-        test_itoa_assert(NULL, 'd');
-        test_itoa_assert(buffer, 0);
-        test_itoa_assert(buffer, 1);
-        test_itoa_assert(buffer, -1);
-        test_itoa_assert(buffer, 37);
-        test_itoa_assert(buffer, -37);
-    }
-
     {
         char buffer[KERNAUX_UTOA_MIN_BUFFER_SIZE + 3];
 
diff --git a/tests/test_ntoa_assert.c b/tests/test_ntoa_assert.c
new file mode 100644
index 00000000..5fb42aba
--- /dev/null
+++ b/tests/test_ntoa_assert.c
@@ -0,0 +1,152 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <kernaux/assert.h>
+#include <kernaux/ntoa.h>
+
+#include <assert.h>
+#include <setjmp.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define VALID_LONG_PREFIX "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+#define TOO_LONG_PREFIX   "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+static jmp_buf jmpbuf;
+
+static unsigned int assert_count_exp = 0;
+static unsigned int assert_count_ctr = 0;
+
+static const char *assert_last_file = NULL;
+static int assert_last_line = 0;
+static const char *assert_last_msg = NULL;
+
+static void assert_cb(
+    const char *const file,
+    const int line,
+    const char *const msg
+) {
+    ++assert_count_ctr;
+
+    assert_last_file = file;
+    assert_last_line = line;
+    assert_last_msg = msg;
+
+    longjmp(jmpbuf, 1);
+}
+
+static void test_utoa_assert(char *const buffer, const int base)
+{
+    if (setjmp(jmpbuf) == 0) {
+        kernaux_utoa(0, buffer, base, NULL);
+    } else {
+        assert(assert_count_ctr == ++assert_count_exp);
+        assert(strstr(assert_last_file, "src/ntoa.c") != NULL);
+        assert(assert_last_line != 0);
+        assert(assert_last_msg != NULL);
+
+        assert_last_file = NULL;
+        assert_last_line = 0;
+        assert_last_msg = NULL;
+    }
+}
+
+static void test_itoa_assert(char *const buffer, const int base)
+{
+    if (setjmp(jmpbuf) == 0) {
+        kernaux_itoa(0, buffer, base, NULL);
+    } else {
+        assert(assert_count_ctr == ++assert_count_exp);
+        assert(strstr(assert_last_file, "src/ntoa.c") != NULL);
+        assert(assert_last_line != 0);
+        assert(assert_last_msg != NULL);
+
+        assert_last_file = NULL;
+        assert_last_line = 0;
+        assert_last_msg = NULL;
+    }
+}
+
+static const char *str_end(const char *str)
+{
+    for (;; ++str) if (*str == '\0') return str;
+}
+
+int main()
+{
+    kernaux_assert_cb = assert_cb;
+
+    if (setjmp(jmpbuf) != 0) abort();
+
+    {
+        char buffer[KERNAUX_UTOA_MIN_BUFFER_SIZE + KERNAUX_NTOA_MAX_PREFIX_LEN];
+
+        const char *const end1 =
+            kernaux_utoa(123, buffer, 'd', VALID_LONG_PREFIX);
+        assert(strcmp(buffer, VALID_LONG_PREFIX"123") == 0);
+        assert(end1 == str_end(buffer));
+        assert(assert_count_ctr == assert_count_exp);
+        assert(assert_last_file == NULL);
+        assert(assert_last_line == 0);
+        assert(assert_last_msg == NULL);
+
+        if (setjmp(jmpbuf) == 0) {
+            kernaux_utoa(123, buffer, 'd', TOO_LONG_PREFIX);
+        } else {
+            assert(strcmp(buffer, VALID_LONG_PREFIX) == 0);
+            assert(assert_count_ctr == ++assert_count_exp);
+            assert(strstr(assert_last_file, "src/ntoa.c") != NULL);
+            assert(assert_last_line != 0);
+            assert(strcmp(assert_last_msg, "prefix is too long") == 0);
+            assert_last_file = NULL;
+            assert_last_line = 0;
+            assert_last_msg = NULL;
+        }
+
+        test_utoa_assert(NULL, 'd');
+        test_utoa_assert(buffer, 0);
+        test_utoa_assert(buffer, 1);
+        test_utoa_assert(buffer, -1);
+        test_utoa_assert(buffer, 37);
+        test_utoa_assert(buffer, -37);
+    }
+
+    if (setjmp(jmpbuf) != 0) abort();
+
+    {
+        char buffer[KERNAUX_ITOA_MIN_BUFFER_SIZE + KERNAUX_NTOA_MAX_PREFIX_LEN];
+
+        const char *const end1 =
+            kernaux_itoa(123, buffer, 'd', VALID_LONG_PREFIX);
+        assert(strcmp(buffer, VALID_LONG_PREFIX"123") == 0);
+        assert(end1 == str_end(buffer));
+        assert(assert_count_ctr == assert_count_exp);
+        assert(assert_last_file == NULL);
+        assert(assert_last_line == 0);
+        assert(assert_last_msg == NULL);
+
+        if (setjmp(jmpbuf) == 0) {
+            kernaux_itoa(123, buffer, 'd', TOO_LONG_PREFIX);
+        } else {
+            assert(strcmp(buffer, VALID_LONG_PREFIX) == 0);
+            assert(assert_count_ctr == ++assert_count_exp);
+            assert(strstr(assert_last_file, "src/ntoa.c") != NULL);
+            assert(assert_last_line != 0);
+            assert(strcmp(assert_last_msg, "prefix is too long") == 0);
+            assert_last_file = NULL;
+            assert_last_line = 0;
+            assert_last_msg = NULL;
+        }
+
+        test_itoa_assert(NULL, 'd');
+        test_itoa_assert(buffer, 0);
+        test_itoa_assert(buffer, 1);
+        test_itoa_assert(buffer, -1);
+        test_itoa_assert(buffer, 37);
+        test_itoa_assert(buffer, -37);
+    }
+
+    return 0;
+}
diff --git a/tests/test_pfa_assert.c b/tests/test_pfa_assert.c
index f215f8ce..b574ebed 100644
--- a/tests/test_pfa_assert.c
+++ b/tests/test_pfa_assert.c
@@ -6,11 +6,12 @@
 #include <kernaux/pfa.h>
 
 #include <assert.h>
+#include <setjmp.h>
 #include <stddef.h>
+#include <stdlib.h>
 
 static unsigned int count = 0;
-
-static void test();
+static jmp_buf jmpbuf;
 
 static void assert_cb(
     __attribute__((unused))
@@ -21,53 +22,82 @@ static void assert_cb(
     const char *const str
 ) {
     ++count;
+    longjmp(jmpbuf, 1);
 }
 
 int main()
 {
-    kernaux_assert_cb = NULL;
-    test();
+    if (setjmp(jmpbuf) != 0) abort();
 
     kernaux_assert_cb = assert_cb;
-    test();
-
-    return 0;
-}
-
-void test()
-{
-    unsigned int acc = 0;
 
     struct KernAux_PFA pfa;
-    KernAux_PFA_initialize(&pfa);
-
-    KernAux_PFA_initialize(NULL);
-    if (kernaux_assert_cb) assert(count == ++acc);
-
-    assert(!KernAux_PFA_is_available(NULL, KERNAUX_PFA_PAGE_SIZE));
-    if (kernaux_assert_cb) assert(count == ++acc);
 
-    assert(!KernAux_PFA_is_available(&pfa, 123));
-    if (kernaux_assert_cb) assert(count == ++acc);
+    if (setjmp(jmpbuf) == 0) {
+        KernAux_PFA_initialize(&pfa);
+    } else {
+        assert(count == 0);
+    }
+
+    if (setjmp(jmpbuf) == 0) {
+        KernAux_PFA_initialize(NULL);
+    } else {
+        assert(count == 1);
+    }
+
+    if (setjmp(jmpbuf) == 0) {
+        assert(!KernAux_PFA_is_available(NULL, KERNAUX_PFA_PAGE_SIZE));
+    } else {
+        assert(count == 2);
+    }
+
+    if (setjmp(jmpbuf) == 0) {
+        assert(!KernAux_PFA_is_available(&pfa, 123));
+    } else {
+        assert(count == 3);
+    }
+
+    if (setjmp(jmpbuf) == 0) {
+        KernAux_PFA_mark_available(NULL, 0, KERNAUX_PFA_PAGE_SIZE);
+    } else {
+        assert(count == 4);
+    }
+
+    if (setjmp(jmpbuf) == 0) {
+        KernAux_PFA_mark_available(&pfa, KERNAUX_PFA_PAGE_SIZE, 0);
+    } else {
+        assert(count == 5);
+    }
+
+    if (setjmp(jmpbuf) == 0) {
+        KernAux_PFA_mark_unavailable(NULL, 0, KERNAUX_PFA_PAGE_SIZE);
+    } else {
+        assert(count == 6);
+    }
+
+    if (setjmp(jmpbuf) == 0) {
+        KernAux_PFA_mark_unavailable(&pfa, KERNAUX_PFA_PAGE_SIZE, 0);
+    } else {
+        assert(count == 7);
+    }
+
+    if (setjmp(jmpbuf) == 0) {
+        assert(KernAux_PFA_alloc_pages(NULL, KERNAUX_PFA_PAGE_SIZE) == 0);
+    } else {
+        assert(count == 8);
+    }
+
+    if (setjmp(jmpbuf) == 0) {
+        KernAux_PFA_free_pages(NULL, KERNAUX_PFA_PAGE_SIZE, KERNAUX_PFA_PAGE_SIZE);
+    } else {
+        assert(count == 9);
+    }
+
+    if (setjmp(jmpbuf) == 0) {
+        KernAux_PFA_free_pages(&pfa, 123, KERNAUX_PFA_PAGE_SIZE);
+    } else {
+        assert(count == 10);
+    }
 
-    KernAux_PFA_mark_available(NULL, 0, KERNAUX_PFA_PAGE_SIZE);
-    if (kernaux_assert_cb) assert(count == ++acc);
-
-    KernAux_PFA_mark_available(&pfa, KERNAUX_PFA_PAGE_SIZE, 0);
-    if (kernaux_assert_cb) assert(count == ++acc);
-
-    KernAux_PFA_mark_unavailable(NULL, 0, KERNAUX_PFA_PAGE_SIZE);
-    if (kernaux_assert_cb) assert(count == ++acc);
-
-    KernAux_PFA_mark_unavailable(&pfa, KERNAUX_PFA_PAGE_SIZE, 0);
-    if (kernaux_assert_cb) assert(count == ++acc);
-
-    assert(KernAux_PFA_alloc_pages(NULL, KERNAUX_PFA_PAGE_SIZE) == 0);
-    if (kernaux_assert_cb) assert(count == ++acc);
-
-    KernAux_PFA_free_pages(NULL, KERNAUX_PFA_PAGE_SIZE, KERNAUX_PFA_PAGE_SIZE);
-    if (kernaux_assert_cb) assert(count == ++acc);
-
-    KernAux_PFA_free_pages(&pfa, 123, KERNAUX_PFA_PAGE_SIZE);
-    if (kernaux_assert_cb) assert(count == ++acc);
+    return 0;
 }