Today, find_proxy_manager() may return a proxy manager that is about to be freed. This happens when the proxy manager's reference count reaches zero, but proxy_manager_destroy() has not removed the proxy manager from the apartment proxy list.
Fix this by only incrementing the reference count if it was nonzero. If the reference count is zero, proxy_manager_destroy() will proceed to destroy the proxy manager after the current thread releases the apartment lock (apt->cs).
Granted, this is fragile and far from elegant, but it seems like a safe approach for the time being. Also, the critical section and "safe" refcount increment will prevent the following race condition scenario:
- Thread X: A proxy manager's refcount reaches 0 and is about to be released.
- Thread Y tries to grab it, calls AddRef, notices it returns 1, and drops it.
- Thread Z tries to grab it, calls AddRef, notices it returns 2, and returns it.
- Thread X then proceeds to remove it from the list and free the object.
-- v5: combase: Prevent use-after-free due to a race with proxy_manager_destroy. combase: Compare AddRef() return value against 1 instead of 0 in find_proxy_manager.