Fix possible crash in DomainResolver.

App::CallDelayed() could be queued twice for a single key, if before
the delayed call we cleared entry in _attempts and created it again.
This commit is contained in:
John Preston 2019-03-20 13:23:14 +04:00
parent 8acd47bf2f
commit a59353df9f
2 changed files with 10 additions and 4 deletions

View File

@ -453,7 +453,7 @@ void DomainResolver::resolve(const AttemptKey &key) {
auto hosts = DnsDomains();
std::random_device rd;
ranges::shuffle(hosts, std::mt19937(rd()));
_attempts.emplace(key, std::move(hosts));
_attempts.emplace(key, Attempts{ std::move(hosts) });
sendNextRequest(key);
}
@ -478,12 +478,13 @@ void DomainResolver::sendNextRequest(const AttemptKey &key) {
if (i == end(_attempts)) {
return;
}
auto &hosts = i->second;
auto &attempts = i->second;
auto &hosts = attempts.hosts;
const auto host = hosts.back();
hosts.pop_back();
if (!hosts.empty()) {
App::CallDelayed(kSendNextTimeout, this, [=] {
App::CallDelayed(kSendNextTimeout, &attempts.guard, [=] {
sendNextRequest(key);
});
}

View File

@ -91,6 +91,11 @@ private:
QStringList ips;
crl::time expireAt = 0;
};
struct Attempts {
std::vector<QString> hosts;
base::has_weak_ptr guard;
};
void resolve(const AttemptKey &key);
@ -110,7 +115,7 @@ private:
crl::time expireAt)> _callback;
QNetworkAccessManager _manager;
std::map<AttemptKey, std::vector<QString>> _attempts;
std::map<AttemptKey, Attempts> _attempts;
std::map<AttemptKey, std::vector<ServiceWebRequest>> _requests;
std::map<AttemptKey, CacheEntry> _cache;
crl::time _lastTimestamp = 0;