-
Notifications
You must be signed in to change notification settings - Fork 168
stats: Fix crash with dangling pointers. #1151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
stats: Fix crash with dangling pointers. #1151
Conversation
|
Can one of the admins verify this patch? |
Greptile OverviewGreptile SummaryReplaces per-node recursive lock with per-handler mutex and atomic flag to prevent timer handlers from executing on destroyed objects during library shutdown. The solution moves synchronization from Key changes:
Confidence Score: 4/5
Important Files ChangedFile Analysis
Sequence DiagramsequenceDiagram
participant App as Application Thread
participant Timer as Timer Thread
participant Handler as timer_handler Object
participant Node as timer_node_t
Note over App,Node: Registration Phase
App->>Timer: register_timer_event(handler)
Timer->>Node: allocate timer_node_t
Timer->>Node: handler.store(handler_ptr)
Note over App,Node: Normal Timer Expiration
Timer->>Timer: process_registered_timers()
Timer->>Node: handler_ptr = handler.load()
Timer->>Handler: safe_handle_timer_expired(data)
Handler->>Handler: trylock() m_handle_mutex
Handler->>Handler: check m_destroy_in_progress
alt Lock acquired and not destroying
Handler->>Handler: handle_timer_expired(data)
Handler->>Handler: unlock()
else Lock failed or destroying
Handler->>Timer: skip execution
end
Note over App,Node: Destruction Phase
App->>Handler: set_destroying_state(true)
Handler->>Handler: m_destroy_in_progress.exchange(true)
App->>Timer: unregister_timers_event_and_delete()
Timer->>Timer: remove_all_timers(handler)
Timer->>Node: handler.store(nullptr)
Timer->>Handler: delete handler
Handler->>Handler: ~timer_handler()
Handler->>Handler: lock() m_handle_mutex (waits if timer running)
Handler->>Handler: unlock()
Note over Handler: Safe to destroy - no timers running
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additional Comments (7)
-
src/vma/event/delta_timer.cpp, line 97 (link)syntax: comparing atomic pointer without
.load()- should benode->handler.load() == handler -
src/vma/event/delta_timer.cpp, line 105 (link)syntax: comparing atomic pointer without
.load()- should benode->handler.load() != handler -
src/vma/event/delta_timer.cpp, line 112 (link)syntax: assigning to atomic pointer without
.store()- should benode->handler.store(NULL)ornode->handler.store(nullptr) -
src/vma/event/delta_timer.cpp, line 128 (link)syntax: comparing atomic pointer without
.load()- should benode->handler.load() == handler -
src/vma/event/delta_timer.cpp, line 133 (link)syntax: comparing atomic pointer without
.load()- should benode_tmp->handler.load() != handler -
src/vma/event/delta_timer.cpp, line 139 (link)syntax: assigning to atomic pointer without
.store()- should benode_tmp->handler.store(nullptr) -
src/vma/event/delta_timer.cpp, line 57 (link)syntax: assigning to atomic pointer without
.store()- should benode->handler.store(handler)
10 files reviewed, 8 comments
| void safe_handle_timer_expired(void* user_data) { | ||
| if(!m_destroy_in_progress.load()) { | ||
| if (m_handle_mutex.trylock() == 0) { | ||
| handle_timer_expired(user_data); | ||
| m_handle_mutex.unlock(); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: race condition: checking m_destroy_in_progress and trylock() are not atomic - thread can pass the check but destructor can start before trylock() succeeds, allowing handle_timer_expired() to run on partially destroyed object. the check should happen after acquiring the lock:
| void safe_handle_timer_expired(void* user_data) { | |
| if(!m_destroy_in_progress.load()) { | |
| if (m_handle_mutex.trylock() == 0) { | |
| handle_timer_expired(user_data); | |
| m_handle_mutex.unlock(); | |
| } | |
| } | |
| } | |
| void safe_handle_timer_expired(void* user_data) { | |
| if (m_handle_mutex.trylock() == 0) { | |
| if(!m_destroy_in_progress.load()) { | |
| handle_timer_expired(user_data); | |
| } | |
| m_handle_mutex.unlock(); | |
| } | |
| } |
fabd923 to
cc0191b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
10 files reviewed, 1 comment
| m_handle_mutex.unlock(); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
syntax: extra closing brace causes syntax error - remove this line
| } |
cc0191b to
2a18d4f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additional Comments (1)
-
src/vma/sock/sockinfo_tcp.cpp, line 4814 (link)syntax: atomic assignment requires
.store()- direct assignment tostd::atomicmay not be thread-safe
10 files reviewed, 2 comments
src/vma/sock/sockinfo_tcp.cpp
Outdated
| iter->handler->handle_timer_expired(iter->user_data); | ||
| timer_handler * handler = iter->handler.load(); | ||
| __log_funcall("timer expired on %p", handler); | ||
| handler->safe_handle_timer_expired(iter->user_data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: missing null check - handler can be null if timer was removed concurrently
| handler->safe_handle_timer_expired(iter->user_data); | |
| if (handler) { | |
| handler->safe_handle_timer_expired(iter->user_data); | |
| } |
2a18d4f to
d5b2b9e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
10 files reviewed, 1 comment
src/vma/event/timer_handler.h
Outdated
| } | ||
| m_handle_mutex.unlock(); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: inconsistent indentation - uses spaces instead of tabs like the rest of the file
| } | |
| } |
d5b2b9e to
3f811e8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additional Comments (1)
-
src/vma/event/delta_timer.cpp, line 31-32 (link)syntax:
!_node_->handlerdoesn't compile -handleris nowstd::atomic<timer_handler*>and requires.load()
10 files reviewed, 2 comments
9033bcf to
16f6842
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
10 files reviewed, no comments
Description
Sometimes it happens, that timer handlers are destroyed, but it still can run in timer thread. Current solution with
lock_timercan't prevent this in case of closing the library. The new solution uses mutex for every handler and prevent execution of the handler in case of destruction, and pause destruction, when the handler is running.What
Fix crash with dangling pointers in timers.
Change type
What kind of change does this PR introduce?
Check list