From 0d34c02c7624200d80b95f99c25da5c4a3f1141f Mon Sep 17 00:00:00 2001 From: Will Koehler Date: Thu, 22 Jun 2023 19:35:16 -0400 Subject: [PATCH] Fix race condition starting CacheCleanupThread (#586) This fixes two race conditions 1. Thread execution may start before `CacheCleanupThread.new` returns the class instance. In this case `t` is not yet defined inside the thread block and results in a "undefined method `sleepy_run' for nil:NilClass" error. 2. Thread execution may start before member variables `@store`, `@interval`, etc are initialized in `CacheCleanupThread#initialize` This results in "undefined method '*' for nil:NilClass" in should_cleanup? (this error only occurs after the first race condition is fixed) More detail: A subclassed thread is scheduled for execution as soon as `super` is called. The code block of the thread may start to execute before the class is fully instantiated. See https://www.ruby-forum.com/t/thread-super-should-be-first-line-or-last-line/150617 --- lib/mini_profiler/storage/memory_store.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mini_profiler/storage/memory_store.rb b/lib/mini_profiler/storage/memory_store.rb index 63475761..25bd05d2 100644 --- a/lib/mini_profiler/storage/memory_store.rb +++ b/lib/mini_profiler/storage/memory_store.rb @@ -10,11 +10,11 @@ class MemoryStore < AbstractStore class CacheCleanupThread < Thread def initialize(interval, cycle, store) - super @store = store @interval = interval @cycle = cycle @cycle_count = 1 + super end def should_cleanup? @@ -78,7 +78,7 @@ def initialize_cleanup_thread(args = {}) cleanup_cycle = args.fetch(:cleanup_cycle) { CLEANUP_CYCLE } t = CacheCleanupThread.new(cleanup_interval, cleanup_cycle, self) do until Thread.current[:should_exit] do - t.sleepy_run + Thread.current.sleepy_run end end at_exit { t[:should_exit] = true }