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

Side by Side Diff: chrome/browser/image_decoder.cc

Issue 1068743002: Fix two race conditions in ImageDecoder. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 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 unified diff | Download patch
« no previous file with comments | « chrome/browser/image_decoder.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/image_decoder.h" 5 #include "chrome/browser/image_decoder.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "chrome/browser/browser_process.h" 8 #include "chrome/browser/browser_process.h"
9 #include "chrome/common/chrome_utility_messages.h" 9 #include "chrome/common/chrome_utility_messages.h"
10 #include "content/public/browser/browser_thread.h" 10 #include "content/public/browser/browser_thread.h"
(...skipping 18 matching lines...) Expand all
29 // A single ImageDecoder instance should live for the life of the program. 29 // A single ImageDecoder instance should live for the life of the program.
30 // Explicitly add a reference so the object isn't deleted. 30 // Explicitly add a reference so the object isn't deleted.
31 AddRef(); 31 AddRef();
32 } 32 }
33 33
34 ImageDecoder::~ImageDecoder() { 34 ImageDecoder::~ImageDecoder() {
35 } 35 }
36 36
37 ImageDecoder::ImageRequest::ImageRequest( 37 ImageDecoder::ImageRequest::ImageRequest(
38 const scoped_refptr<base::SequencedTaskRunner>& task_runner) 38 const scoped_refptr<base::SequencedTaskRunner>& task_runner)
39 : task_runner_(task_runner) { 39 : task_runner_(task_runner), weak_factory_(this) {
40 } 40 }
41 41
42 ImageDecoder::ImageRequest::~ImageRequest() { 42 ImageDecoder::ImageRequest::~ImageRequest() {
43 // Destructor needs to run on the same thread as |OnImageDecoded| and
44 // |OnDecodeImageFailed|, otherwise cancellation is racy.
45 DCHECK(task_runner_->RunsTasksOnCurrentThread());
43 ImageDecoder::Cancel(this); 46 ImageDecoder::Cancel(this);
44 } 47 }
45 48
49 base::WeakPtr<ImageDecoder::ImageRequest>
50 ImageDecoder::ImageRequest::GetWeakPtr() {
51 return weak_factory_.GetWeakPtr();
52 }
53
46 // static 54 // static
47 void ImageDecoder::Start(ImageRequest* image_request, 55 void ImageDecoder::Start(ImageRequest* image_request,
48 const std::string& image_data) { 56 const std::string& image_data) {
49 StartWithOptions(image_request, image_data, DEFAULT_CODEC, false); 57 StartWithOptions(image_request, image_data, DEFAULT_CODEC, false);
50 } 58 }
51 59
52 // static 60 // static
53 void ImageDecoder::StartWithOptions(ImageRequest* image_request, 61 void ImageDecoder::StartWithOptions(ImageRequest* image_request,
54 const std::string& image_data, 62 const std::string& image_data,
55 ImageCodec image_codec, 63 ImageCodec image_codec,
56 bool shrink_to_fit) { 64 bool shrink_to_fit) {
65 g_decoder.Pointer()->StartWithOptionsImpl(image_request, image_data,
66 image_codec, shrink_to_fit);
67 }
68
69 void ImageDecoder::StartWithOptionsImpl(ImageRequest* image_request,
70 const std::string& image_data,
71 ImageCodec image_codec,
72 bool shrink_to_fit) {
57 DCHECK(image_request); 73 DCHECK(image_request);
58 DCHECK(image_request->task_runner()); 74 DCHECK(image_request->task_runner());
75
76 int request_id;
77 {
78 base::AutoLock lock(map_lock_);
79 request_id = image_request_id_counter_++;
80 image_request_id_map_.insert(std::make_pair(
81 request_id, std::make_pair(image_request->task_runner(),
82 image_request->GetWeakPtr())));
83 }
59 BrowserThread::PostTask( 84 BrowserThread::PostTask(
60 BrowserThread::IO, FROM_HERE, 85 BrowserThread::IO, FROM_HERE,
61 base::Bind( 86 base::Bind(
62 &ImageDecoder::DecodeImageInSandbox, 87 &ImageDecoder::DecodeImageInSandbox, this, request_id,
63 g_decoder.Pointer(), image_request,
64 std::vector<unsigned char>(image_data.begin(), image_data.end()), 88 std::vector<unsigned char>(image_data.begin(), image_data.end()),
65 image_codec, shrink_to_fit)); 89 image_codec, shrink_to_fit));
66 } 90 }
67 91
68 // static 92 // static
69 void ImageDecoder::Cancel(ImageRequest* image_request) { 93 void ImageDecoder::Cancel(ImageRequest* image_request) {
70 DCHECK(image_request); 94 DCHECK(image_request);
71 g_decoder.Pointer()->CancelImpl(image_request); 95 g_decoder.Pointer()->CancelImpl(image_request);
72 } 96 }
73 97
74 void ImageDecoder::DecodeImageInSandbox( 98 void ImageDecoder::DecodeImageInSandbox(
75 ImageRequest* image_request, 99 int request_id,
76 const std::vector<unsigned char>& image_data, 100 const std::vector<unsigned char>& image_data,
77 ImageCodec image_codec, 101 ImageCodec image_codec,
78 bool shrink_to_fit) { 102 bool shrink_to_fit) {
79 DCHECK_CURRENTLY_ON(BrowserThread::IO); 103 DCHECK_CURRENTLY_ON(BrowserThread::IO);
80 if (!utility_process_host_) { 104 if (!utility_process_host_) {
81 StartBatchMode(); 105 StartBatchMode();
82 } 106 }
83 if (!utility_process_host_) { 107 if (!utility_process_host_) {
84 // Utility process failed to start; notify delegate and return. 108 // Utility process failed to start; notify delegate and return.
85 // Without this check, we were seeing crashes on startup. Further 109 // Without this check, we were seeing crashes on startup. Further
86 // investigation is needed to determine why the utility process 110 // investigation is needed to determine why the utility process
87 // is failing to start. See crbug.com/472272 111 // is failing to start. See crbug.com/472272
88 image_request->task_runner()->PostTask( 112 OnDecodeImageFailed(request_id);
89 FROM_HERE, base::Bind(&ImageRequest::OnDecodeImageFailed,
90 base::Unretained(image_request)));
91 return; 113 return;
92 } 114 }
93 115
94 last_request_ = base::TimeTicks::Now(); 116 last_request_ = base::TimeTicks::Now();
95 base::AutoLock lock(map_lock_);
96 image_request_id_map_.insert(
97 std::make_pair(image_request_id_counter_, image_request));
98 117
99 switch (image_codec) { 118 switch (image_codec) {
100 case ROBUST_JPEG_CODEC: 119 case ROBUST_JPEG_CODEC:
101 utility_process_host_->Send(new ChromeUtilityMsg_RobustJPEGDecodeImage( 120 utility_process_host_->Send(
102 image_data, image_request_id_counter_)); 121 new ChromeUtilityMsg_RobustJPEGDecodeImage(image_data, request_id));
103 break; 122 break;
104 case DEFAULT_CODEC: 123 case DEFAULT_CODEC:
105 utility_process_host_->Send(new ChromeUtilityMsg_DecodeImage( 124 utility_process_host_->Send(new ChromeUtilityMsg_DecodeImage(
106 image_data, shrink_to_fit, image_request_id_counter_)); 125 image_data, shrink_to_fit, request_id));
107 break; 126 break;
108 } 127 }
109
110 ++image_request_id_counter_;
111 } 128 }
112 129
113 void ImageDecoder::CancelImpl(ImageRequest* image_request) { 130 void ImageDecoder::CancelImpl(ImageRequest* image_request) {
131 // Cancellation needs to be done on the same thread as |OnImageDecoded| and
132 // |OnDecodeImageFailed|, otherwise there's a race where these functions can
133 // run while the request is being cancelled.
134 // This is also necessary for WeakPtr<> correctness.
135 DCHECK(image_request->task_runner()->RunsTasksOnCurrentThread());
Lei Zhang 2015/04/07 22:29:21 The header file makes it sound as though ImageDeco
136
114 base::AutoLock lock(map_lock_); 137 base::AutoLock lock(map_lock_);
115 for (auto it = image_request_id_map_.begin(); 138 for (auto it = image_request_id_map_.begin();
116 it != image_request_id_map_.end();) { 139 it != image_request_id_map_.end();) {
117 if (it->second == image_request) { 140 if (it->second.second.get() == image_request) {
118 image_request_id_map_.erase(it++); 141 image_request_id_map_.erase(it++);
119 } else { 142 } else {
120 ++it; 143 ++it;
121 } 144 }
122 } 145 }
123 } 146 }
124 147
125 void ImageDecoder::StartBatchMode() { 148 void ImageDecoder::StartBatchMode() {
126 DCHECK_CURRENTLY_ON(BrowserThread::IO); 149 DCHECK_CURRENTLY_ON(BrowserThread::IO);
127 utility_process_host_ = 150 utility_process_host_ =
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 return handled; 186 return handled;
164 } 187 }
165 188
166 void ImageDecoder::OnDecodeImageSucceeded( 189 void ImageDecoder::OnDecodeImageSucceeded(
167 const SkBitmap& decoded_image, 190 const SkBitmap& decoded_image,
168 int request_id) { 191 int request_id) {
169 DCHECK_CURRENTLY_ON(BrowserThread::IO); 192 DCHECK_CURRENTLY_ON(BrowserThread::IO);
170 base::AutoLock lock(map_lock_); 193 base::AutoLock lock(map_lock_);
171 auto it = image_request_id_map_.find(request_id); 194 auto it = image_request_id_map_.find(request_id);
172 if (it != image_request_id_map_.end()) { 195 if (it != image_request_id_map_.end()) {
173 ImageRequest* image_request = it->second; 196 auto& task_runner = it->second.first;
174 image_request->task_runner()->PostTask( 197 base::WeakPtr<ImageRequest> image_request = it->second.second;
175 FROM_HERE, base::Bind(&ImageRequest::OnImageDecoded, 198 task_runner->PostTask(FROM_HERE, base::Bind(&ImageRequest::OnImageDecoded,
176 base::Unretained(image_request), decoded_image)); 199 image_request, decoded_image));
177 200
178 image_request_id_map_.erase(it); 201 image_request_id_map_.erase(it);
179 } 202 }
180 } 203 }
181 204
182 void ImageDecoder::OnDecodeImageFailed(int request_id) { 205 void ImageDecoder::OnDecodeImageFailed(int request_id) {
183 DCHECK_CURRENTLY_ON(BrowserThread::IO); 206 DCHECK_CURRENTLY_ON(BrowserThread::IO);
184 base::AutoLock lock(map_lock_); 207 base::AutoLock lock(map_lock_);
185 auto it = image_request_id_map_.find(request_id); 208 auto it = image_request_id_map_.find(request_id);
186 if (it != image_request_id_map_.end()) { 209 if (it != image_request_id_map_.end()) {
187 ImageRequest* image_request = it->second; 210 auto& task_runner = it->second.first;
188 image_request->task_runner()->PostTask( 211 base::WeakPtr<ImageRequest> image_request = it->second.second;
189 FROM_HERE, base::Bind(&ImageRequest::OnDecodeImageFailed, 212 task_runner->PostTask(
190 base::Unretained(image_request))); 213 FROM_HERE,
214 base::Bind(&ImageRequest::OnDecodeImageFailed, image_request));
191 215
192 image_request_id_map_.erase(it); 216 image_request_id_map_.erase(it);
193 } 217 }
194 } 218 }
OLDNEW
« no previous file with comments | « chrome/browser/image_decoder.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698