From 452e1a57a67fbb46d8e0b0b119ceb0646d619f99 Mon Sep 17 00:00:00 2001 From: Mazunki Hoksaas Date: Wed, 8 Apr 2026 15:15:15 +0200 Subject: [PATCH 1/4] mark noreturn functions it's not guaranteed that all implementations of `reboot()` are terminating calls. `reboot_os()`, externally defined at `src/arch/{x86_64,i686}/apic_asm.asm` both terminate, but this seems to be an implementation detail of the x86 architecture. --- api/arch.hpp | 4 ++-- api/os.hpp | 2 +- src/kernel/syscalls.cpp | 2 +- src/platform/x86_pc/acpi.cpp | 3 +-- src/platform/x86_pc/acpi.hpp | 2 +- src/platform/x86_pc/platform.cpp | 5 ++--- 6 files changed, 8 insertions(+), 10 deletions(-) diff --git a/api/arch.hpp b/api/arch.hpp index c5b72b49e1..19c8185804 100644 --- a/api/arch.hpp +++ b/api/arch.hpp @@ -27,8 +27,8 @@ #include -extern void __arch_poweroff(); -extern void __arch_reboot(); +[[noreturn]] extern void __arch_poweroff(); +[[noreturn]] extern void __arch_reboot(); extern void __arch_enable_legacy_irq(uint8_t); extern void __arch_disable_legacy_irq(uint8_t); extern void __arch_system_deactivate(); diff --git a/api/os.hpp b/api/os.hpp index 827d71c68a..255724497c 100644 --- a/api/os.hpp +++ b/api/os.hpp @@ -86,7 +86,7 @@ namespace os { // /** Trigger unrecoverable error and output diagnostics **/ - __attribute__((noreturn)) + [[noreturn]] void panic(const char* why) noexcept; /** Default behavior after panic **/ diff --git a/src/kernel/syscalls.cpp b/src/kernel/syscalls.cpp index b7b555dbd7..8b801d91c6 100644 --- a/src/kernel/syscalls.cpp +++ b/src/kernel/syscalls.cpp @@ -118,7 +118,7 @@ extern kernel::ctor_t __plugin_ctors_end; * Print EOT character to stderr, to signal outside that PANIC output completed * If the handler returns, go to (permanent) sleep **/ -void os::panic(const char* why) noexcept +[[noreturn]] void os::panic(const char* why) noexcept { cpu_enable_panicking(); if (kernel::panics() > 4) double_fault(why); diff --git a/src/platform/x86_pc/acpi.cpp b/src/platform/x86_pc/acpi.cpp index 5ea85789c6..e110eff0d7 100644 --- a/src/platform/x86_pc/acpi.cpp +++ b/src/platform/x86_pc/acpi.cpp @@ -393,8 +393,7 @@ namespace x86 { } } - __attribute__((noreturn)) - void ACPI::shutdown() + [[noreturn]] void ACPI::shutdown() { asm("cli"); diff --git a/src/platform/x86_pc/acpi.hpp b/src/platform/x86_pc/acpi.hpp index 68f3871661..687847b20f 100644 --- a/src/platform/x86_pc/acpi.hpp +++ b/src/platform/x86_pc/acpi.hpp @@ -102,7 +102,7 @@ namespace x86 { } static void reboot(); - static void shutdown(); + [[noreturn]] static void shutdown(); private: void discover(); diff --git a/src/platform/x86_pc/platform.cpp b/src/platform/x86_pc/platform.cpp index 15ef037877..3a720d030a 100644 --- a/src/platform/x86_pc/platform.cpp +++ b/src/platform/x86_pc/platform.cpp @@ -147,12 +147,11 @@ void __arch_disable_legacy_irq(uint8_t irq) x86::APIC::disable_irq(irq); } -void __arch_poweroff() +[[noreturn]] void __arch_poweroff() { x86::ACPI::shutdown(); - __builtin_unreachable(); } -void __arch_reboot() +[[noreturn]] void __arch_reboot() { x86::ACPI::reboot(); __builtin_unreachable(); From 6286eda11ae08957ac2d578b028f80638d64d07e Mon Sep 17 00:00:00 2001 From: Mazunki Hoksaas Date: Wed, 8 Apr 2026 15:20:56 +0200 Subject: [PATCH 2/4] prevent panic cycle before libc is ready --- src/kernel/syscalls.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/kernel/syscalls.cpp b/src/kernel/syscalls.cpp index 8b801d91c6..59932efc9a 100644 --- a/src/kernel/syscalls.cpp +++ b/src/kernel/syscalls.cpp @@ -124,6 +124,10 @@ extern kernel::ctor_t __plugin_ctors_end; if (kernel::panics() > 4) double_fault(why); const int current_cpu = SMP::cpu_id(); + if (!kernel::libc_initialized()) { + kprint("FATAL: panic before libc\n"); + panic_epilogue(why); + } #ifdef INCLUDEOS_SMP_ENABLE SMP::global_lock(); From f3f79f89ea9d914298f06eed2f834c6fc09f5f5d Mon Sep 17 00:00:00 2001 From: Mazunki Hoksaas Date: Wed, 8 Apr 2026 15:22:31 +0200 Subject: [PATCH 3/4] formatting --- api/expects | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/api/expects b/api/expects index 9ff218539a..9bbdaf0dbd 100644 --- a/api/expects +++ b/api/expects @@ -34,16 +34,19 @@ #include inline void __expect_emit_failure(std::string_view msg, std::string_view panic_text) { #ifndef UNITTESTS + #ifdef INCLUDEOS_SMP_ENABLE SMP::global_lock(); #endif + std::fprintf(stderr, "%.*s\n", int(msg.size()), msg.data()); fflush(NULL); #ifdef INCLUDEOS_SMP_ENABLE SMP::global_unlock(); #endif os::panic(std::string(panic_text).c_str()); -#else // TEST + +#else // UNITTESTS (void) panic_text; // throw here to allow tests to capture the error #include From 856c69c88847ae7370a506adea4432d4d1dc6276 Mon Sep 17 00:00:00 2001 From: Mazunki Hoksaas Date: Wed, 8 Apr 2026 15:23:19 +0200 Subject: [PATCH 4/4] abort during infinite exception cycle --- api/expects | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/api/expects b/api/expects index 9bbdaf0dbd..b030711b56 100644 --- a/api/expects +++ b/api/expects @@ -32,6 +32,19 @@ #endif #include +#include + +inline bool __expect_is_recursive() { +#ifndef UNITTESTS + static volatile bool in_failure = false; + if (in_failure) return true; + in_failure = true; + return false; +#else + return false; +#endif +} + inline void __expect_emit_failure(std::string_view msg, std::string_view panic_text) { #ifndef UNITTESTS @@ -55,13 +68,36 @@ inline void __expect_emit_failure(std::string_view msg, std::string_view panic_t } template -inline void __expect_failf(const char *err_prefix, const char * /*cond*/, const char *file, int line, const char *func, std::format_string fmt, Args&&... args){ +inline void __expect_failf(const char *err_prefix, const char * cond, const char *file, int line, const char *func, std::format_string fmt, Args&&... args){ + if (__expect_is_recursive()) { + kprint("Fatal Expects/Ensures recursion. (libc not initialized?)\n"); + + kprint("Condition was '"); + kprint(cond); kprint("' @ "); + kprint(file); kprint(":"); + kprint(func); kprint(" with fmt="); + kprint(fmt.get().data()); kprint("\n"); + + // os::shutdown(); + __arch_poweroff(); + } auto reason_msg = std::format(fmt, std::forward(args)...); auto error_msg = std::format("{}:{}:{}: {}: {}", file, line, func, err_prefix, reason_msg); __expect_emit_failure(error_msg, reason_msg); } inline void __expect_failf(const char *err_prefix, const char *cond, const char *file, int line, const char *func){ + if (__expect_is_recursive()) { + kprint("Fatal Expects/Ensures recursion (libc not initialized?)\n"); + + kprint("Condition was '"); + kprint(cond); kprint("' @ "); + kprint(file); kprint(":"); + kprint(func); kprint("\n"); + + // os::shutdown(); + __arch_poweroff(); + } auto reason_msg = std::format("{}: {}", err_prefix, cond); auto error_msg = std::format("{}:{}:{}: {}", file, line, func, err_prefix); __expect_emit_failure(error_msg, reason_msg);