Skip to content

Lock-order-inversion deadlock in NotificationCenter #5159

@aleks-f

Description

@aleks-f

Summary

NotificationCenter methods call observer methods (start(), disable()) while holding the internal mutex, creating a lock-order-inversion with Observer's mutex.

Deadlock Scenario

Thread A (eg. SocketRreactor::run()):

  1. Observer::notify() holds Observer mutex (M0)
  2. Handler calls removeEventHandler() (documented as safe)
  3. hasObserver() waits for NotificationCenter mutex (M1)

Thread B (shutdown):

  1. removeObserver() holds NotificationCenter mutex (M1)
  2. disable() waits for Observer mutex (M0)

Result: Deadlock (M0 → M1, M1 → M0)

Affected Methods

  • addObserver() - calls start() under lock
  • removeObserver() - calls disable() under lock
  • clear() - calls disable() under lock

Fix

Release lock before calling observer methods:

void NotificationCenter::addObserver(const AbstractObserver& observer)
{
	AbstractObserverPtr pObserver = observer.clone();
	{
		RWLock::ScopedWriteLock lock(_mutex);
		_observers.push_back(pObserver);
	}
	// Start outside the lock to avoid deadlock with Observer mutex
	pObserver->start();
}

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions