Skip to content

Commit 7900ec2

Browse files
author
Kaloyan Chehlarski
committed
Fix invalid iterator access inside LockManager
The code for storing and removing access locks relied on the (incorrect) assumption that one can store an iterator to an element inside a container (or rather, a container inside a container), add more elements, and then expect the iterator to still be valid. In practice, however, the Visual C++ runtime will reallocate the entirety of the storage after only two lock requests, which results in a crash when visiting Facebook while logged in. This change modifies the code to remove any storage of iterators, and replaces it with a more expensive, but safe, string lookup followed by an iteration through a list. This should not cause any significant slowdown, however, since the elements stored inside these containers are very short-lived, and low in number. Fixes: QTBUG-133093 Change-Id: I3870109cd047b761ac2cdacfe4164cd59182fd1d Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/619468 Reviewed-by: Peter Varga <[email protected]> (cherry picked from commit 71353f2) Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/620292 Reviewed-by: Qt Cherry-pick Bot <[email protected]>
1 parent eb31082 commit 7900ec2

File tree

1 file changed

+25
-21
lines changed

1 file changed

+25
-21
lines changed

chromium/content/browser/locks/lock_manager.cc

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ class LockManager::BucketState {
167167
// queue.
168168
void BreakFront(std::list<Lock>& request_queue) {
169169
Lock& broken_lock = request_queue.front();
170-
lock_id_to_iterator_.erase(broken_lock.lock_id());
170+
lock_id_to_resource_name_.erase(broken_lock.lock_id());
171171
broken_lock.Break();
172172
request_queue.pop_front();
173173
}
@@ -186,11 +186,10 @@ class LockManager::BucketState {
186186
std::list<Lock>& request_queue = resource_names_to_requests_[name];
187187
while (!request_queue.empty() && request_queue.front().is_granted())
188188
BreakFront(request_queue);
189-
request_queue.emplace_front(name, mode, lock_id, receiver_state,
189+
auto& queued_request = request_queue.emplace_front(name, mode, lock_id, receiver_state,
190190
std::move(request));
191-
auto it = request_queue.begin();
192-
lock_id_to_iterator_.emplace(it->lock_id(), it);
193-
it->Grant(lock_manager_, receiver_state.bucket_id);
191+
lock_id_to_resource_name_.emplace(queued_request.lock_id(), queued_request.name());
192+
queued_request.Grant(lock_manager_, receiver_state.bucket_id);
194193
}
195194

196195
void AddRequest(int64_t lock_id,
@@ -211,26 +210,25 @@ class LockManager::BucketState {
211210
return;
212211
}
213212

214-
request_queue.emplace_back(name, mode, lock_id, receiver_state,
213+
auto& queued_request = request_queue.emplace_back(name, mode, lock_id, receiver_state,
215214
std::move(request));
216-
auto it = --(request_queue.end());
217-
lock_id_to_iterator_.emplace(it->lock_id(), it);
215+
lock_id_to_resource_name_.emplace(queued_request.lock_id(), queued_request.name());
218216
if (can_grant) {
219-
it->Grant(lock_manager_, receiver_state.bucket_id);
217+
queued_request.Grant(lock_manager_, receiver_state.bucket_id);
220218
}
221219
}
222220

223221
void EraseLock(int64_t lock_id, storage::BucketId bucket_id) {
224222
// Note - the two lookups here could be replaced with one if the
225-
// lock_id_to_iterator_ map also stored a reference to the request queue.
226-
auto iterator_it = lock_id_to_iterator_.find(lock_id);
227-
if (iterator_it == lock_id_to_iterator_.end())
223+
// lock_id_to_resource_name_ map also stored a reference to the request queue.
224+
auto iterator_it = lock_id_to_resource_name_.find(lock_id);
225+
if (iterator_it == lock_id_to_resource_name_.end())
228226
return;
229227

230-
auto lock_it = iterator_it->second;
231-
lock_id_to_iterator_.erase(iterator_it);
228+
const std::string resource_name = iterator_it->second;
229+
lock_id_to_resource_name_.erase(iterator_it);
232230

233-
auto request_it = resource_names_to_requests_.find(lock_it->name());
231+
auto request_it = resource_names_to_requests_.find(resource_name);
234232
if (request_it == resource_names_to_requests_.end())
235233
return;
236234

@@ -239,14 +237,20 @@ class LockManager::BucketState {
239237
auto check_it = request_queue.begin();
240238
bool found = false;
241239
for (; check_it != request_queue.end(); ++check_it) {
242-
found = check_it == lock_it;
240+
found = check_it->name() == resource_name;
243241
if (found)
244242
break;
245243
}
246244
DCHECK(found);
247245
#endif
248246

249-
request_queue.erase(lock_it);
247+
for (auto queue_it = request_queue.begin(); queue_it != request_queue.end(); ++queue_it) {
248+
if (queue_it->lock_id() == lock_id) {
249+
request_queue.erase(queue_it);
250+
break;
251+
}
252+
}
253+
250254
if (request_queue.empty()) {
251255
resource_names_to_requests_.erase(request_it);
252256
return;
@@ -274,7 +278,7 @@ class LockManager::BucketState {
274278
}
275279
}
276280

277-
bool IsEmpty() const { return lock_id_to_iterator_.empty(); }
281+
bool IsEmpty() const { return lock_id_to_resource_name_.empty(); }
278282

279283
std::pair<std::vector<blink::mojom::LockInfoPtr>,
280284
std::vector<blink::mojom::LockInfoPtr>>
@@ -305,9 +309,9 @@ class LockManager::BucketState {
305309
// request queue.
306310
base::flat_map<std::string, std::list<Lock>> resource_names_to_requests_;
307311

308-
// BucketState::lock_id_to_iterator_ maps a lock's id to the
309-
// iterator pointing to its location in its associated request queue.
310-
base::flat_map<int64_t, std::list<Lock>::iterator> lock_id_to_iterator_;
312+
// BucketState::lock_id_to_resource_name_ maps a lock's id to the
313+
// name of the requested resource.
314+
base::flat_map<int64_t, std::string> lock_id_to_resource_name_;
311315

312316
// Any OriginState is owned by a LockManager so a raw pointer back to an
313317
// OriginState's owning LockManager is safe.

0 commit comments

Comments
 (0)