Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(302)

Unified Diff: ui/message_center/views/message_list_view.cc

Issue 2836023002: Fix use-after-free in MessageListView. (Closed)
Patch Set: rebase Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/message_center/views/message_center_view.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/message_center/views/message_list_view.cc
diff --git a/ui/message_center/views/message_list_view.cc b/ui/message_center/views/message_list_view.cc
index bd731b70ee0047419d31b7e9bcce308a5658cc07..06cce39c28a3b0defe6e473284cfcea9da3e3661 100644
--- a/ui/message_center/views/message_list_view.cc
+++ b/ui/message_center/views/message_list_view.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <algorithm>
+
#include "base/command_line.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
@@ -100,6 +102,20 @@ void MessageListView::AddNotificationAt(MessageView* view, int index) {
void MessageListView::RemoveNotification(MessageView* view) {
DCHECK_EQ(view->parent(), this);
+ // TODO(yhananda): We should consider consolidating clearing_all_views_,
+ // deleting_views_ and deleted_when_done_.
+ if (std::find(clearing_all_views_.begin(), clearing_all_views_.end(), view) !=
+ clearing_all_views_.end() ||
+ deleting_views_.find(view) != deleting_views_.end() ||
+ deleted_when_done_.find(view) != deleted_when_done_.end()) {
+ // Let's skip deleting the view if it's already scheduled for deleting.
+ // Even if we check clearing_all_views_ here, we actualy have no idea
+ // whether the view is due to be removed or not because it could be in its
+ // animation before removal.
+ // In short, we could delete the view twice even if we check these three
+ // lists.
+ return;
+ }
if (GetContentsBounds().IsEmpty()) {
delete view;
@@ -120,6 +136,11 @@ void MessageListView::RemoveNotification(MessageView* view) {
void MessageListView::UpdateNotification(MessageView* view,
const Notification& notification) {
+ // Skip updating the notification being cleared
+ if (std::find(clearing_all_views_.begin(), clearing_all_views_.end(), view) !=
+ clearing_all_views_.end())
+ return;
+
int index = GetIndexOf(view);
DCHECK_LE(0, index); // GetIndexOf is negative if not a child.
@@ -242,6 +263,15 @@ void MessageListView::ClearAllClosableNotifications(
continue;
if (child->IsPinned())
continue;
+ if (deleting_views_.find(child) != deleting_views_.end() ||
+ deleted_when_done_.find(child) != deleted_when_done_.end()) {
+ // We don't check clearing_all_views_ here, so this can lead to a
+ // notification being deleted twice. Even if we do check it, there is a
+ // problem similar to the problem in RemoveNotification(), it could be
+ // currently in its animation before removal, and we could similarly
+ // delete it twice. This is a bug.
+ continue;
+ }
clearing_all_views_.push_back(child);
}
if (clearing_all_views_.empty()) {
@@ -298,7 +328,9 @@ bool MessageListView::IsValidChild(const views::View* child) const {
deleting_views_.find(const_cast<views::View*>(child)) ==
deleting_views_.end() &&
deleted_when_done_.find(const_cast<views::View*>(child)) ==
- deleted_when_done_.end();
+ deleted_when_done_.end() &&
+ std::find(clearing_all_views_.begin(), clearing_all_views_.end(),
+ child) == clearing_all_views_.end();
}
void MessageListView::DoUpdateIfPossible() {
« no previous file with comments | « ui/message_center/views/message_center_view.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698