From 4aac6f2ee3494a593d79eeea389c77037e025adc Mon Sep 17 00:00:00 2001 From: Quinton Miller Date: Thu, 31 Oct 2024 18:20:50 +0800 Subject: [PATCH] Protect constant initializers with mutex on Windows (#15134) `Crystal::System::FileDescriptor#@@reader_thread` is initialized before `Crystal::System::Fiber::RESERVED_STACK_SIZE` which creates a race condition. Regression from #14947 --- src/crystal/once.cr | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/crystal/once.cr b/src/crystal/once.cr index 1e6243669809..56eea2be693a 100644 --- a/src/crystal/once.cr +++ b/src/crystal/once.cr @@ -11,9 +11,6 @@ # :nodoc: class Crystal::OnceState @rec = [] of Bool* - {% if flag?(:preview_mt) %} - @mutex = Mutex.new(:reentrant) - {% end %} def once(flag : Bool*, initializer : Void*) unless flag.value @@ -29,7 +26,13 @@ class Crystal::OnceState end end - {% if flag?(:preview_mt) %} + # on Win32, `Crystal::System::FileDescriptor#@@reader_thread` spawns a new + # thread even without the `preview_mt` flag, and the thread can also reference + # Crystal constants, leading to race conditions, so we always enable the mutex + # TODO: can this be improved? + {% if flag?(:preview_mt) || flag?(:win32) %} + @mutex = Mutex.new(:reentrant) + def once(flag : Bool*, initializer : Void*) unless flag.value @mutex.synchronize do