From a59353df9f93b244c72b93e73224d5eac4f6fee7 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 20 Mar 2019 13:23:14 +0400 Subject: [PATCH] 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. --- Telegram/SourceFiles/mtproto/special_config_request.cpp | 7 ++++--- Telegram/SourceFiles/mtproto/special_config_request.h | 7 ++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/mtproto/special_config_request.cpp b/Telegram/SourceFiles/mtproto/special_config_request.cpp index d8093ec3b1..8b57956b70 100644 --- a/Telegram/SourceFiles/mtproto/special_config_request.cpp +++ b/Telegram/SourceFiles/mtproto/special_config_request.cpp @@ -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); }); } diff --git a/Telegram/SourceFiles/mtproto/special_config_request.h b/Telegram/SourceFiles/mtproto/special_config_request.h index cba2e71b02..be12d759fa 100644 --- a/Telegram/SourceFiles/mtproto/special_config_request.h +++ b/Telegram/SourceFiles/mtproto/special_config_request.h @@ -91,6 +91,11 @@ private: QStringList ips; crl::time expireAt = 0; + }; + struct Attempts { + std::vector hosts; + base::has_weak_ptr guard; + }; void resolve(const AttemptKey &key); @@ -110,7 +115,7 @@ private: crl::time expireAt)> _callback; QNetworkAccessManager _manager; - std::map> _attempts; + std::map _attempts; std::map> _requests; std::map _cache; crl::time _lastTimestamp = 0;