From b49c466ff33c758b93ac3e7b62d968e8ca851f3b Mon Sep 17 00:00:00 2001 From: Quinton Miller Date: Mon, 8 Jan 2024 19:16:42 +0800 Subject: [PATCH] Windows: Reserve stack space on non-main threads for crash recovery --- src/crystal/system/win32/thread.cr | 13 ++++++++++++- src/exception/call_stack/stackwalk.cr | 3 ++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/crystal/system/win32/thread.cr b/src/crystal/system/win32/thread.cr index 9a13bfb4dc03..5dbcbabbfad9 100644 --- a/src/crystal/system/win32/thread.cr +++ b/src/crystal/system/win32/thread.cr @@ -12,13 +12,24 @@ module Crystal::System::Thread @system_handle = GC.beginthreadex( security: Pointer(Void).null, stack_size: LibC::UInt.zero, - start_address: ->(data : Void*) { data.as(::Thread).start; LibC::UInt.zero }, + start_address: ->Thread.thread_proc(Void*), arglist: self.as(Void*), initflag: LibC::UInt.zero, thrdaddr: Pointer(LibC::UInt).null, ) end + def self.thread_proc(data : Void*) : LibC::UInt + # ensure that even in the case of stack overflow there is enough reserved + # stack space for recovery (for the main thread this is done in + # `Exception::CallStack.setup_crash_handler`) + stack_size = Crystal::System::Fiber::RESERVED_STACK_SIZE + LibC.SetThreadStackGuarantee(pointerof(stack_size)) + + data.as(::Thread).start + LibC::UInt.zero + end + def self.current_handle : Handle # `GetCurrentThread` returns a _constant_ and is only meaningful as an # argument to Win32 APIs; to uniquely identify it we must duplicate the handle diff --git a/src/exception/call_stack/stackwalk.cr b/src/exception/call_stack/stackwalk.cr index f49c87fae623..ede0e0a803de 100644 --- a/src/exception/call_stack/stackwalk.cr +++ b/src/exception/call_stack/stackwalk.cr @@ -51,7 +51,8 @@ struct Exception::CallStack end) # ensure that even in the case of stack overflow there is enough reserved - # stack space for recovery + # stack space for recovery (for other threads this is done in + # `Crystal::System::Thread.thread_proc`) stack_size = Crystal::System::Fiber::RESERVED_STACK_SIZE LibC.SetThreadStackGuarantee(pointerof(stack_size)) end