Skip to content

3.0.0

Latest

Choose a tag to compare

@LK-Simon LK-Simon released this 13 Aug 18:54

Make Observer registration ownership and notification mutation memory-safe

Problem

Observer registration currently returns a raw owning IObserverHandle*. This creates several memory-safety risks:

  • Losing the returned pointer permanently leaks the registration handle and lifetime-control reference.
  • Registering the same Observer more than once returns the same raw pointer, allowing multiple callers to believe they own it and potentially double-delete it.
  • ThreadSafeObservable allocates a temporary Observer vector for every notification, creating unnecessary heap traffic and fragmentation risk on embedded systems.
  • Registering or unregistering Observers during notification can invalidate active containers, particularly with ObservableWithBuckets.
  • Surviving handles are not immediately invalidated when Observable destruction begins.

Proposed changes

  • Change RegisterObserver() and RegisterObserverAs() to return:
    • ObserverHandlePtr
    • Defined as std::unique_ptr<IObserverHandle>
  • Reject duplicate registrations with DuplicateObserverRegistrationException.
  • Ensure every registration has exactly one owning handle.
  • Automatically unregister when the owning handle is reset or destroyed.
  • Invalidate all surviving handles during Observable destruction.
  • Replace per-notification Observer-vector copies with indexed, allocation-free traversal.
  • Use deferred tombstone compaction so Observers can safely unregister themselves or other Observers during notification.
  • Apply equivalent mutation-safe behavior to:
    • Observable
    • ThreadSafeObservable
    • ObservableWithBuckets
  • Preserve exception safety when notification callbacks throw.
  • Update documentation and examples for RAII handle ownership.
  • Add regression coverage for:
    • Duplicate registration rejection
    • Self-unregistration during ordinary notification
    • Self-unregistration during bucketed notification
    • Thread-safe concurrent unregistration
    • Handles outliving their Observable
    • Observable destruction concurrent with handle destruction
    • Exceptions during callbacks and unregistration

Version impact

This changes the public registration return type and ownership contract.

Target version: 3.0.0

Acceptance criteria

  • Registration returns an owning smart pointer.
  • Discarding or resetting a registration handle cannot leak it.
  • Duplicate registration cannot create ambiguous ownership.
  • Registration changes during notification cannot invalidate traversal.
  • Thread-safe notification performs no temporary Observer-list allocation.
  • Handles are invalidated when Observable destruction begins.
  • Strict C++14 tests pass with warnings treated as errors.
  • UBSan tests pass.
  • Heap analysis reports no leaked allocations.