Commit 9a3ba05f authored by Min Qin's avatar Min Qin Committed by Commit Bot

Fix an use-after-free issue when dragging a download on windows

The use-after-free is introduced in the following call sequence:
1. DataObjectImpl::GetData() calls DragDownloadFile::Wait(),
  which starts nested runloop and wait for download to complete.
2. DragDownloadFile::DownloadCompleted() is called, and it calls
   DataObjectImpl::OnDownloadCompleted().
3. OnDownloadCompleted() creates a new StoredDataInfo object,
   that clears up the scoped_refptr of DragDownloadFile in the
   StoredDataInfo. As a result, DragDownloadFile is deleted.
4. The nested runloop started in DragDownloadFile::Wait() should
   finish now, but the return statement touches the state_
   member variable on the deleted object,

This CL breaks the above sequence by checking the weakptr in 4 first
before accessing the state_ member variable

BUG=968303

Change-Id: Ie1266d344fe102f73451bda9f996e29d9bd00a31
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1827488Reviewed-by: default avatarXing Liu <xingliu@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Commit-Queue: Min Qin <qinmin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#700914}
parent c528b0ff
......@@ -239,9 +239,13 @@ void DragDownloadFile::Start(ui::DownloadFileObserver* observer) {
bool DragDownloadFile::Wait() {
CheckThread();
// Store the weakptr in a local variable as |this| may be deleted while
// waiting for the nested RunLoop.
auto ref = weak_ptr_factory_.GetWeakPtr();
if (state_ == STARTED)
nested_loop_.Run();
return state_ == SUCCESS;
// If the weakptr is destroyed, the download should be successful.
return !ref.get() || state_ == SUCCESS;
}
void DragDownloadFile::Stop() {
......
......@@ -842,8 +842,7 @@ static void DuplicateMedium(CLIPFORMAT source_clipformat,
DataObjectImpl::StoredDataInfo::StoredDataInfo(const FORMATETC& format_etc,
STGMEDIUM* medium)
: format_etc(format_etc), medium(medium), owns_medium(true) {
}
: format_etc(format_etc), medium(medium), owns_medium(true) {}
DataObjectImpl::StoredDataInfo::~StoredDataInfo() {
if (owns_medium) {
......@@ -920,7 +919,8 @@ HRESULT DataObjectImpl::GetData(FORMATETC* format_etc, STGMEDIUM* medium) {
// If medium is NULL, delay-rendering will be used.
if (content->medium) {
DuplicateMedium(content->format_etc.cfFormat, content->medium, medium);
} else {
return S_OK;
}
// Fail all GetData() attempts for DownloadURL data if the drag and drop
// operation is still in progress.
if (in_drag_loop_)
......@@ -951,13 +951,10 @@ HRESULT DataObjectImpl::GetData(FORMATETC* format_etc, STGMEDIUM* medium) {
return DV_E_FORMATETC;
}
}
// The stored data should have been updated with the final version.
// So we just need to call this function again to retrieve it.
return GetData(format_etc, medium);
}
return S_OK;
}
}
return DV_E_FORMATETC;
......
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