[regression] [BufferQueue] Race condition in BufferQueue::compositor_acquire could underflow shared_ptr refcount and delete prematurely, crash.
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
Mir |
Fix Released
|
High
|
Alexandros Frantzis | ||
mir (Ubuntu) |
Fix Released
|
High
|
Unassigned |
Bug Description
[regression] [BufferQueue] Race condition in BufferQueue:
In compositor_acquire you see:
auto const& acquired_buffer = buffer_
if (buffer_to_release)
return acquired_buffer; // <=== shared_ptr copy constructed from acquired_ptr without any lock
}
However if the lock has been moved before the return, then it's possible two concurrent threads have the same value of acquired_buffer and will both construct shared_ptrs whose object has the same refcount (which is one too little). Later when destructed this could produce an underflow of the refcount, destroying the buffer prematurely and crashing.
I think the simple solution is to ensure you have constructed your thread's own shared_ptr result before giving up the lock. So change:
auto const& acquired_buffer = buffer_
to:
std:
Related branches
- Alberto Aguirre (community): Needs Fixing
- Daniel van Vugt: Needs Fixing
- Alan Griffiths: Abstain
- PS Jenkins bot (community): Approve (continuous-integration)
-
Diff: 162 lines (+76/-7)2 files modifiedsrc/server/compositor/buffer_queue.cpp (+17/-0)
tests/unit-tests/compositor/test_buffer_queue.cpp (+59/-7)
- PS Jenkins bot (community): Approve (continuous-integration)
- Daniel van Vugt: Needs Fixing
- Alberto Aguirre (community): Approve
- Alan Griffiths: Abstain
-
Diff: 162 lines (+73/-10)2 files modifiedsrc/server/compositor/buffer_queue.cpp (+10/-3)
tests/unit-tests/compositor/test_buffer_queue.cpp (+63/-7)
Changed in mir: | |
status: | New → Triaged |
importance: | Undecided → High |
milestone: | none → 0.2.0 |
tags: | added: regression |
Changed in mir: | |
status: | Triaged → Fix Committed |
assignee: | nobody → Alexandros Frantzis (afrantzis) |
Changed in mir: | |
status: | Fix Committed → Fix Released |
Changed in mir (Ubuntu): | |
importance: | Undecided → High |
status: | New → Fix Released |
My understanding is that std::shared_ptr can handle the scenario described in a thread-safe manner without any external synchronization (the control block of a shared_ptr which is what is shared between instances is thread safe).
However, there may still be some races around compositor_ acquire( ) and resizing in give_buffer_ to_client( ) that need further investigation.