From 75360de76a2a84cea03892ef76765adc34ad8984 Mon Sep 17 00:00:00 2001 From: Julien Portalier Date: Wed, 19 Jun 2024 13:07:39 +0200 Subject: [PATCH] Fix: panic musn't allocate error message string --- src/crystal/system/panic.cr | 43 +++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/src/crystal/system/panic.cr b/src/crystal/system/panic.cr index 3e421ce05d02..7bed6403c105 100644 --- a/src/crystal/system/panic.cr +++ b/src/crystal/system/panic.cr @@ -1,19 +1,34 @@ module Crystal::System - # Prints a system error message on the standard error then exits. + # Prints a system error message on the standard error then exits with an error + # status. # # Prefer `RuntimeError.from_os_error` unless you can't allocate any memory # (e.g. stop the world). - def self.panic(syscall_name : String, error = nil) - error ||= - {% if flag?(:unix) %} - Errno.value - {% elsif flag?(:win32) %} - WinError.value - {% else %} - {% raise "Unsupported target" %} - {% end %} - Crystal::System.print_error("%s failed with %s (%s)\n", - syscall_name, error.message, error.to_s) - exit 1 - end + {% if flag?(:unix) %} + def self.panic(syscall_name : String, error : Errno = Errno.value) : NoReturn + buffer = LibC.strerror(error.value) + message = Bytes.new(buffer, LibC.strlen(buffer)) + Crystal::System.print_error("%s failed with ", syscall_name) + Crystal::System.print_error(message) + Crystal::System.print_error(" (%s)\n", error.to_s) + exit 1 + end + {% elsif flag?(:win32) %} + def self.panic(syscall_name : String, error : WinError = WinError.value) : NoReturn + buffer = uninitialized UInt16[256] + size = LibC.FormatMessageW(LibC::FORMAT_MESSAGE_FROM_SYSTEM, nil, error.value, 0, buffer, buffer.size, nil) + message = buffer.to_slice[0, size] + Crystal::System.print_error("%s failed with ", syscall_name) + Crystal::System.print_error(message) + Crystal::System.print_error(" (%s)\n", error.to_s) + exit 1 + end + {% elsif flag?(:wasm32) %} + def self.panic(syscall_name : String, error : WasiError) : NoReturn + Crystal::System.print_error("%s failed with %s (%s)", syscall_name, error.message, error.to_s) + exit 1 + end + {% else %} + {% raise "Unsupported target" %} + {% end %} end