Commit 61a51a16 authored by Paul Jensen's avatar Paul Jensen Committed by Commit Bot

Fix race in ~NetworkChangeNotifier overloads

Some ~NetworkChangeNotifier overloads post destruction to other
threads, which races ~NetworkChangeNotifier's clearing of
g_network_change_notifier.  Clear g_network_change_notifier at
the begining of ~NetworkChangeNotifier overloads to prevent this.

Bug: 965660
Change-Id: If6d792ea0f1badd7c816308646104e0f72ca5b4d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1625307Reviewed-by: default avatarWez <wez@chromium.org>
Reviewed-by: default avatarEric Orth <ericorth@chromium.org>
Commit-Queue: Paul Jensen <pauljensen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#662879}
parent 656db4d1
...@@ -118,6 +118,7 @@ class NetworkChangeNotifierAndroid::BlockingThreadObjects { ...@@ -118,6 +118,7 @@ class NetworkChangeNotifierAndroid::BlockingThreadObjects {
}; };
NetworkChangeNotifierAndroid::~NetworkChangeNotifierAndroid() { NetworkChangeNotifierAndroid::~NetworkChangeNotifierAndroid() {
ClearGlobalPointer();
delegate_->RemoveObserver(this); delegate_->RemoveObserver(this);
} }
......
...@@ -114,7 +114,6 @@ class NetworkChangeNotifier::NetworkChangeCalculator ...@@ -114,7 +114,6 @@ class NetworkChangeNotifier::NetworkChangeCalculator
~NetworkChangeCalculator() override { ~NetworkChangeCalculator() override {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(g_network_change_notifier);
RemoveConnectionTypeObserver(this); RemoveConnectionTypeObserver(this);
RemoveIPAddressObserver(this); RemoveIPAddressObserver(this);
} }
...@@ -174,10 +173,17 @@ class NetworkChangeNotifier::NetworkChangeCalculator ...@@ -174,10 +173,17 @@ class NetworkChangeNotifier::NetworkChangeCalculator
DISALLOW_COPY_AND_ASSIGN(NetworkChangeCalculator); DISALLOW_COPY_AND_ASSIGN(NetworkChangeCalculator);
}; };
NetworkChangeNotifier::~NetworkChangeNotifier() { void NetworkChangeNotifier::ClearGlobalPointer() {
network_change_calculator_.reset(); if (!cleared_global_pointer_) {
cleared_global_pointer_ = true;
DCHECK_EQ(this, g_network_change_notifier); DCHECK_EQ(this, g_network_change_notifier);
g_network_change_notifier = nullptr; g_network_change_notifier = nullptr;
}
}
NetworkChangeNotifier::~NetworkChangeNotifier() {
network_change_calculator_.reset();
ClearGlobalPointer();
} }
// static // static
...@@ -483,92 +489,122 @@ NetworkChangeNotifier* NetworkChangeNotifier::CreateMock() { ...@@ -483,92 +489,122 @@ NetworkChangeNotifier* NetworkChangeNotifier::CreateMock() {
return new MockNetworkChangeNotifier(); return new MockNetworkChangeNotifier();
} }
NetworkChangeNotifier::IPAddressObserver::IPAddressObserver() = default;
NetworkChangeNotifier::IPAddressObserver::~IPAddressObserver() = default;
NetworkChangeNotifier::ConnectionTypeObserver::ConnectionTypeObserver() =
default;
NetworkChangeNotifier::ConnectionTypeObserver::~ConnectionTypeObserver() =
default;
NetworkChangeNotifier::DNSObserver::DNSObserver() = default;
NetworkChangeNotifier::DNSObserver::~DNSObserver() = default;
NetworkChangeNotifier::NetworkChangeObserver::NetworkChangeObserver() = default;
NetworkChangeNotifier::NetworkChangeObserver::~NetworkChangeObserver() =
default;
NetworkChangeNotifier::MaxBandwidthObserver::MaxBandwidthObserver() = default;
NetworkChangeNotifier::MaxBandwidthObserver::~MaxBandwidthObserver() = default;
NetworkChangeNotifier::NetworkObserver::NetworkObserver() = default;
NetworkChangeNotifier::NetworkObserver::~NetworkObserver() = default;
void NetworkChangeNotifier::AddIPAddressObserver(IPAddressObserver* observer) { void NetworkChangeNotifier::AddIPAddressObserver(IPAddressObserver* observer) {
if (g_network_change_notifier) if (g_network_change_notifier) {
g_network_change_notifier->ip_address_observer_list_->AddObserver(observer); observer->observer_list_ =
g_network_change_notifier->ip_address_observer_list_;
observer->observer_list_->AddObserver(observer);
}
} }
void NetworkChangeNotifier::AddConnectionTypeObserver( void NetworkChangeNotifier::AddConnectionTypeObserver(
ConnectionTypeObserver* observer) { ConnectionTypeObserver* observer) {
if (g_network_change_notifier) { if (g_network_change_notifier) {
g_network_change_notifier->connection_type_observer_list_->AddObserver( observer->observer_list_ =
observer); g_network_change_notifier->connection_type_observer_list_;
observer->observer_list_->AddObserver(observer);
} }
} }
void NetworkChangeNotifier::AddDNSObserver(DNSObserver* observer) { void NetworkChangeNotifier::AddDNSObserver(DNSObserver* observer) {
if (g_network_change_notifier) { if (g_network_change_notifier) {
g_network_change_notifier->resolver_state_observer_list_->AddObserver( observer->observer_list_ =
observer); g_network_change_notifier->resolver_state_observer_list_;
observer->observer_list_->AddObserver(observer);
} }
} }
void NetworkChangeNotifier::AddNetworkChangeObserver( void NetworkChangeNotifier::AddNetworkChangeObserver(
NetworkChangeObserver* observer) { NetworkChangeObserver* observer) {
if (g_network_change_notifier) { if (g_network_change_notifier) {
g_network_change_notifier->network_change_observer_list_->AddObserver( observer->observer_list_ =
observer); g_network_change_notifier->network_change_observer_list_;
observer->observer_list_->AddObserver(observer);
} }
} }
void NetworkChangeNotifier::AddMaxBandwidthObserver( void NetworkChangeNotifier::AddMaxBandwidthObserver(
MaxBandwidthObserver* observer) { MaxBandwidthObserver* observer) {
if (g_network_change_notifier) { if (g_network_change_notifier) {
g_network_change_notifier->max_bandwidth_observer_list_->AddObserver( observer->observer_list_ =
observer); g_network_change_notifier->max_bandwidth_observer_list_;
observer->observer_list_->AddObserver(observer);
} }
} }
void NetworkChangeNotifier::AddNetworkObserver(NetworkObserver* observer) { void NetworkChangeNotifier::AddNetworkObserver(NetworkObserver* observer) {
DCHECK(AreNetworkHandlesSupported()); DCHECK(AreNetworkHandlesSupported());
if (g_network_change_notifier) { if (g_network_change_notifier) {
g_network_change_notifier->network_observer_list_->AddObserver(observer); observer->observer_list_ =
g_network_change_notifier->network_observer_list_;
observer->observer_list_->AddObserver(observer);
} }
} }
void NetworkChangeNotifier::RemoveIPAddressObserver( void NetworkChangeNotifier::RemoveIPAddressObserver(
IPAddressObserver* observer) { IPAddressObserver* observer) {
if (g_network_change_notifier) { if (observer->observer_list_) {
g_network_change_notifier->ip_address_observer_list_->RemoveObserver( observer->observer_list_->RemoveObserver(observer);
observer); observer->observer_list_.reset();
} }
} }
void NetworkChangeNotifier::RemoveConnectionTypeObserver( void NetworkChangeNotifier::RemoveConnectionTypeObserver(
ConnectionTypeObserver* observer) { ConnectionTypeObserver* observer) {
if (g_network_change_notifier) { if (observer->observer_list_) {
g_network_change_notifier->connection_type_observer_list_->RemoveObserver( observer->observer_list_->RemoveObserver(observer);
observer); observer->observer_list_.reset();
} }
} }
void NetworkChangeNotifier::RemoveDNSObserver(DNSObserver* observer) { void NetworkChangeNotifier::RemoveDNSObserver(DNSObserver* observer) {
if (g_network_change_notifier) { if (observer->observer_list_) {
g_network_change_notifier->resolver_state_observer_list_->RemoveObserver( observer->observer_list_->RemoveObserver(observer);
observer); observer->observer_list_.reset();
} }
} }
void NetworkChangeNotifier::RemoveNetworkChangeObserver( void NetworkChangeNotifier::RemoveNetworkChangeObserver(
NetworkChangeObserver* observer) { NetworkChangeObserver* observer) {
if (g_network_change_notifier) { if (observer->observer_list_) {
g_network_change_notifier->network_change_observer_list_->RemoveObserver( observer->observer_list_->RemoveObserver(observer);
observer); observer->observer_list_.reset();
} }
} }
void NetworkChangeNotifier::RemoveMaxBandwidthObserver( void NetworkChangeNotifier::RemoveMaxBandwidthObserver(
MaxBandwidthObserver* observer) { MaxBandwidthObserver* observer) {
if (g_network_change_notifier) { if (observer->observer_list_) {
g_network_change_notifier->max_bandwidth_observer_list_->RemoveObserver( observer->observer_list_->RemoveObserver(observer);
observer); observer->observer_list_.reset();
} }
} }
void NetworkChangeNotifier::RemoveNetworkObserver(NetworkObserver* observer) { void NetworkChangeNotifier::RemoveNetworkObserver(NetworkObserver* observer) {
DCHECK(AreNetworkHandlesSupported()); if (observer->observer_list_) {
if (g_network_change_notifier) { observer->observer_list_->RemoveObserver(observer);
g_network_change_notifier->network_observer_list_->RemoveObserver(observer); observer->observer_list_.reset();
} }
} }
......
...@@ -109,10 +109,14 @@ class NET_EXPORT NetworkChangeNotifier { ...@@ -109,10 +109,14 @@ class NET_EXPORT NetworkChangeNotifier {
virtual void OnIPAddressChanged() = 0; virtual void OnIPAddressChanged() = 0;
protected: protected:
IPAddressObserver() {} IPAddressObserver();
virtual ~IPAddressObserver() {} virtual ~IPAddressObserver();
private: private:
friend NetworkChangeNotifier;
scoped_refptr<base::ObserverListThreadSafe<IPAddressObserver>>
observer_list_;
DISALLOW_COPY_AND_ASSIGN(IPAddressObserver); DISALLOW_COPY_AND_ASSIGN(IPAddressObserver);
}; };
...@@ -126,10 +130,14 @@ class NET_EXPORT NetworkChangeNotifier { ...@@ -126,10 +130,14 @@ class NET_EXPORT NetworkChangeNotifier {
virtual void OnConnectionTypeChanged(ConnectionType type) = 0; virtual void OnConnectionTypeChanged(ConnectionType type) = 0;
protected: protected:
ConnectionTypeObserver() {} ConnectionTypeObserver();
virtual ~ConnectionTypeObserver() {} virtual ~ConnectionTypeObserver();
private: private:
friend NetworkChangeNotifier;
scoped_refptr<base::ObserverListThreadSafe<ConnectionTypeObserver>>
observer_list_;
DISALLOW_COPY_AND_ASSIGN(ConnectionTypeObserver); DISALLOW_COPY_AND_ASSIGN(ConnectionTypeObserver);
}; };
...@@ -148,10 +156,13 @@ class NET_EXPORT NetworkChangeNotifier { ...@@ -148,10 +156,13 @@ class NET_EXPORT NetworkChangeNotifier {
virtual void OnInitialDNSConfigRead(); virtual void OnInitialDNSConfigRead();
protected: protected:
DNSObserver() {} DNSObserver();
virtual ~DNSObserver() {} virtual ~DNSObserver();
private: private:
friend NetworkChangeNotifier;
scoped_refptr<base::ObserverListThreadSafe<DNSObserver>> observer_list_;
DISALLOW_COPY_AND_ASSIGN(DNSObserver); DISALLOW_COPY_AND_ASSIGN(DNSObserver);
}; };
...@@ -185,10 +196,14 @@ class NET_EXPORT NetworkChangeNotifier { ...@@ -185,10 +196,14 @@ class NET_EXPORT NetworkChangeNotifier {
virtual void OnNetworkChanged(ConnectionType type) = 0; virtual void OnNetworkChanged(ConnectionType type) = 0;
protected: protected:
NetworkChangeObserver() {} NetworkChangeObserver();
virtual ~NetworkChangeObserver() {} virtual ~NetworkChangeObserver();
private: private:
friend NetworkChangeNotifier;
scoped_refptr<base::ObserverListThreadSafe<NetworkChangeObserver>>
observer_list_;
DISALLOW_COPY_AND_ASSIGN(NetworkChangeObserver); DISALLOW_COPY_AND_ASSIGN(NetworkChangeObserver);
}; };
...@@ -203,10 +218,14 @@ class NET_EXPORT NetworkChangeNotifier { ...@@ -203,10 +218,14 @@ class NET_EXPORT NetworkChangeNotifier {
ConnectionType type) = 0; ConnectionType type) = 0;
protected: protected:
MaxBandwidthObserver() {} MaxBandwidthObserver();
virtual ~MaxBandwidthObserver() {} virtual ~MaxBandwidthObserver();
private: private:
friend NetworkChangeNotifier;
scoped_refptr<base::ObserverListThreadSafe<MaxBandwidthObserver>>
observer_list_;
DISALLOW_COPY_AND_ASSIGN(MaxBandwidthObserver); DISALLOW_COPY_AND_ASSIGN(MaxBandwidthObserver);
}; };
...@@ -245,10 +264,13 @@ class NET_EXPORT NetworkChangeNotifier { ...@@ -245,10 +264,13 @@ class NET_EXPORT NetworkChangeNotifier {
virtual void OnNetworkMadeDefault(NetworkHandle network) = 0; virtual void OnNetworkMadeDefault(NetworkHandle network) = 0;
protected: protected:
NetworkObserver() {} NetworkObserver();
virtual ~NetworkObserver() {} virtual ~NetworkObserver();
private: private:
friend NetworkChangeNotifier;
scoped_refptr<base::ObserverListThreadSafe<NetworkObserver>> observer_list_;
DISALLOW_COPY_AND_ASSIGN(NetworkObserver); DISALLOW_COPY_AND_ASSIGN(NetworkObserver);
}; };
...@@ -536,6 +558,10 @@ class NET_EXPORT NetworkChangeNotifier { ...@@ -536,6 +558,10 @@ class NET_EXPORT NetworkChangeNotifier {
// have the same type, return it, otherwise return CONNECTION_UNKNOWN. // have the same type, return it, otherwise return CONNECTION_UNKNOWN.
static ConnectionType ConnectionTypeFromInterfaces(); static ConnectionType ConnectionTypeFromInterfaces();
// Clears the global NetworkChangeNotifier pointer. This should be called
// as early as possible in the destructor to prevent races.
void ClearGlobalPointer();
private: private:
friend class HostResolverManagerDnsTest; friend class HostResolverManagerDnsTest;
friend class NetworkChangeNotifierAndroidTest; friend class NetworkChangeNotifierAndroidTest;
...@@ -577,6 +603,9 @@ class NET_EXPORT NetworkChangeNotifier { ...@@ -577,6 +603,9 @@ class NET_EXPORT NetworkChangeNotifier {
// Set true to disable non-test notifications (to prevent flakes in tests). // Set true to disable non-test notifications (to prevent flakes in tests).
static bool test_notifications_only_; static bool test_notifications_only_;
// Indicates if this instance cleared g_network_change_notifier_ yet.
bool cleared_global_pointer_ = false;
DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifier); DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifier);
}; };
......
...@@ -61,6 +61,7 @@ NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia( ...@@ -61,6 +61,7 @@ NetworkChangeNotifierFuchsia::NetworkChangeNotifierFuchsia(
NetworkChangeNotifierFuchsia::~NetworkChangeNotifierFuchsia() { NetworkChangeNotifierFuchsia::~NetworkChangeNotifierFuchsia() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
ClearGlobalPointer();
} }
NetworkChangeNotifier::ConnectionType NetworkChangeNotifier::ConnectionType
......
...@@ -107,7 +107,9 @@ NetworkChangeNotifierLinux::NetworkChangeNotifierLinux( ...@@ -107,7 +107,9 @@ NetworkChangeNotifierLinux::NetworkChangeNotifierLinux(
base::Unretained(blocking_thread_objects_.get()))); base::Unretained(blocking_thread_objects_.get())));
} }
NetworkChangeNotifierLinux::~NetworkChangeNotifierLinux() = default; NetworkChangeNotifierLinux::~NetworkChangeNotifierLinux() {
ClearGlobalPointer();
}
// static // static
NetworkChangeNotifier::NetworkChangeCalculatorParams NetworkChangeNotifier::NetworkChangeCalculatorParams
......
...@@ -56,6 +56,7 @@ NetworkChangeNotifierMac::NetworkChangeNotifierMac() ...@@ -56,6 +56,7 @@ NetworkChangeNotifierMac::NetworkChangeNotifierMac()
} }
NetworkChangeNotifierMac::~NetworkChangeNotifierMac() { NetworkChangeNotifierMac::~NetworkChangeNotifierMac() {
ClearGlobalPointer();
// Delete the ConfigWatcher to join the notifier thread, ensuring that // Delete the ConfigWatcher to join the notifier thread, ensuring that
// StartReachabilityNotifications() has an opportunity to run to completion. // StartReachabilityNotifications() has an opportunity to run to completion.
config_watcher_.reset(); config_watcher_.reset();
......
...@@ -66,7 +66,9 @@ NetworkChangeNotifierPosix::NetworkChangeNotifierPosix( ...@@ -66,7 +66,9 @@ NetworkChangeNotifierPosix::NetworkChangeNotifierPosix(
OnDNSChanged(); OnDNSChanged();
} }
NetworkChangeNotifierPosix::~NetworkChangeNotifierPosix() = default; NetworkChangeNotifierPosix::~NetworkChangeNotifierPosix() {
ClearGlobalPointer();
}
void NetworkChangeNotifierPosix::OnDNSChanged() { void NetworkChangeNotifierPosix::OnDNSChanged() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
......
...@@ -55,6 +55,7 @@ NetworkChangeNotifierWin::NetworkChangeNotifierWin() ...@@ -55,6 +55,7 @@ NetworkChangeNotifierWin::NetworkChangeNotifierWin()
NetworkChangeNotifierWin::~NetworkChangeNotifierWin() { NetworkChangeNotifierWin::~NetworkChangeNotifierWin() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
ClearGlobalPointer();
if (is_watching_) { if (is_watching_) {
CancelIPChangeNotify(&addr_overlapped_); CancelIPChangeNotify(&addr_overlapped_);
addr_watcher_.StopWatching(); addr_watcher_.StopWatching();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment