OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 // TODO(vtl): I currently potentially overflow in doing index calculations. | 5 // TODO(vtl): I currently potentially overflow in doing index calculations. |
6 // E.g., |start_index_| and |current_num_bytes_| fit into a |uint32_t|, but | 6 // E.g., |start_index_| and |current_num_bytes_| fit into a |uint32_t|, but |
7 // their sum may not. This is bad and poses a security risk. (We're currently | 7 // their sum may not. This is bad and poses a security risk. (We're currently |
8 // saved by the limit on capacity -- the maximum size of the buffer, checked in | 8 // saved by the limit on capacity -- the maximum size of the buffer, checked in |
9 // |DataPipe::ValidateOptions()|, is currently sufficiently small. | 9 // |DataPipe::ValidateOptions()|, is currently sufficiently small. |
10 | 10 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 DestroyBufferNoLock(); | 43 DestroyBufferNoLock(); |
44 } | 44 } |
45 AwakeConsumerWaitersForStateChangeNoLock(); | 45 AwakeConsumerWaitersForStateChangeNoLock(); |
46 } | 46 } |
47 | 47 |
48 MojoResult LocalDataPipe::ProducerWriteDataImplNoLock(const void* elements, | 48 MojoResult LocalDataPipe::ProducerWriteDataImplNoLock(const void* elements, |
49 uint32_t* num_bytes, | 49 uint32_t* num_bytes, |
50 bool all_or_none) { | 50 bool all_or_none) { |
51 DCHECK_EQ(*num_bytes % element_num_bytes(), 0u); | 51 DCHECK_EQ(*num_bytes % element_num_bytes(), 0u); |
52 DCHECK_GT(*num_bytes, 0u); | 52 DCHECK_GT(*num_bytes, 0u); |
| 53 DCHECK(consumer_open_no_lock()); |
53 | 54 |
54 size_t num_bytes_to_write = 0; | 55 size_t num_bytes_to_write = 0; |
55 if (may_discard()) { | 56 if (may_discard()) { |
56 if (all_or_none && *num_bytes > capacity_num_bytes()) | 57 if (all_or_none && *num_bytes > capacity_num_bytes()) |
57 return MOJO_RESULT_OUT_OF_RANGE; | 58 return MOJO_RESULT_OUT_OF_RANGE; |
58 | 59 |
59 num_bytes_to_write = std::min(static_cast<size_t>(*num_bytes), | 60 num_bytes_to_write = std::min(static_cast<size_t>(*num_bytes), |
60 capacity_num_bytes()); | 61 capacity_num_bytes()); |
61 if (num_bytes_to_write > capacity_num_bytes() - current_num_bytes_) { | 62 if (num_bytes_to_write > capacity_num_bytes() - current_num_bytes_) { |
62 // Discard as much as needed (discard oldest first). | 63 // Discard as much as needed (discard oldest first). |
63 size_t num_bytes_to_discard = | 64 size_t num_bytes_to_discard = |
64 num_bytes_to_write - (capacity_num_bytes() - current_num_bytes_); | 65 num_bytes_to_write - (capacity_num_bytes() - current_num_bytes_); |
65 start_index_ += num_bytes_to_discard; | 66 start_index_ += num_bytes_to_discard; |
66 start_index_ %= capacity_num_bytes(); | 67 start_index_ %= capacity_num_bytes(); |
67 current_num_bytes_ -= num_bytes_to_discard; | 68 current_num_bytes_ -= num_bytes_to_discard; |
68 } | 69 } |
69 } else { | 70 } else { |
70 if (all_or_none && *num_bytes > capacity_num_bytes() - current_num_bytes_) { | 71 if (all_or_none && *num_bytes > capacity_num_bytes() - current_num_bytes_) { |
71 return (*num_bytes > capacity_num_bytes()) ? MOJO_RESULT_OUT_OF_RANGE : | 72 // Don't return "should wait" since you can't wait for a specified amount |
72 MOJO_RESULT_SHOULD_WAIT; | 73 // of data. |
| 74 return MOJO_RESULT_OUT_OF_RANGE; |
73 } | 75 } |
74 | 76 |
75 num_bytes_to_write = std::min(static_cast<size_t>(*num_bytes), | 77 num_bytes_to_write = std::min(static_cast<size_t>(*num_bytes), |
76 capacity_num_bytes() - current_num_bytes_); | 78 capacity_num_bytes() - current_num_bytes_); |
77 } | 79 } |
78 if (num_bytes_to_write == 0) | 80 if (num_bytes_to_write == 0) |
79 return MOJO_RESULT_SHOULD_WAIT; | 81 return MOJO_RESULT_SHOULD_WAIT; |
80 | 82 |
81 // The amount we can write in our first |memcpy()|. | 83 // The amount we can write in our first |memcpy()|. |
82 size_t num_bytes_to_write_first = | 84 size_t num_bytes_to_write_first = |
(...skipping 20 matching lines...) Expand all Loading... |
103 AwakeConsumerWaitersForStateChangeNoLock(); | 105 AwakeConsumerWaitersForStateChangeNoLock(); |
104 | 106 |
105 *num_bytes = static_cast<uint32_t>(num_bytes_to_write); | 107 *num_bytes = static_cast<uint32_t>(num_bytes_to_write); |
106 return MOJO_RESULT_OK; | 108 return MOJO_RESULT_OK; |
107 } | 109 } |
108 | 110 |
109 MojoResult LocalDataPipe::ProducerBeginWriteDataImplNoLock( | 111 MojoResult LocalDataPipe::ProducerBeginWriteDataImplNoLock( |
110 void** buffer, | 112 void** buffer, |
111 uint32_t* buffer_num_bytes, | 113 uint32_t* buffer_num_bytes, |
112 bool all_or_none) { | 114 bool all_or_none) { |
| 115 DCHECK(consumer_open_no_lock()); |
| 116 |
113 size_t max_num_bytes_to_write = GetMaxNumBytesToWriteNoLock(); | 117 size_t max_num_bytes_to_write = GetMaxNumBytesToWriteNoLock(); |
114 // TODO(vtl): Consider this return value. | 118 if (all_or_none && *buffer_num_bytes > max_num_bytes_to_write) { |
115 if (all_or_none && *buffer_num_bytes > max_num_bytes_to_write) | 119 // Don't return "should wait" since you can't wait for a specified amount of |
| 120 // data. |
116 return MOJO_RESULT_OUT_OF_RANGE; | 121 return MOJO_RESULT_OUT_OF_RANGE; |
| 122 } |
117 | 123 |
118 // Don't go into a two-phase write if there's no room. | 124 // Don't go into a two-phase write if there's no room. |
119 if (max_num_bytes_to_write == 0) | 125 if (max_num_bytes_to_write == 0) |
120 return MOJO_RESULT_SHOULD_WAIT; | 126 return MOJO_RESULT_SHOULD_WAIT; |
121 | 127 |
122 size_t write_index = | 128 size_t write_index = |
123 (start_index_ + current_num_bytes_) % capacity_num_bytes(); | 129 (start_index_ + current_num_bytes_) % capacity_num_bytes(); |
124 EnsureBufferNoLock(); | 130 EnsureBufferNoLock(); |
125 *buffer = buffer_.get() + write_index; | 131 *buffer = buffer_.get() + write_index; |
126 *buffer_num_bytes = static_cast<uint32_t>(max_num_bytes_to_write); | 132 *buffer_num_bytes = static_cast<uint32_t>(max_num_bytes_to_write); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 current_num_bytes_ = 0; | 178 current_num_bytes_ = 0; |
173 AwakeProducerWaitersForStateChangeNoLock(); | 179 AwakeProducerWaitersForStateChangeNoLock(); |
174 } | 180 } |
175 | 181 |
176 MojoResult LocalDataPipe::ConsumerReadDataImplNoLock(void* elements, | 182 MojoResult LocalDataPipe::ConsumerReadDataImplNoLock(void* elements, |
177 uint32_t* num_bytes, | 183 uint32_t* num_bytes, |
178 bool all_or_none) { | 184 bool all_or_none) { |
179 DCHECK_EQ(*num_bytes % element_num_bytes(), 0u); | 185 DCHECK_EQ(*num_bytes % element_num_bytes(), 0u); |
180 DCHECK_GT(*num_bytes, 0u); | 186 DCHECK_GT(*num_bytes, 0u); |
181 | 187 |
182 // TODO(vtl): Think about the error code in this case. | 188 if (all_or_none && *num_bytes > current_num_bytes_) { |
183 if (all_or_none && *num_bytes > current_num_bytes_) | 189 // Don't return "should wait" since you can't wait for a specified amount of |
184 return MOJO_RESULT_OUT_OF_RANGE; | 190 // data. |
| 191 return producer_open_no_lock() ? MOJO_RESULT_OUT_OF_RANGE : |
| 192 MOJO_RESULT_FAILED_PRECONDITION; |
| 193 } |
185 | 194 |
186 size_t num_bytes_to_read = | 195 size_t num_bytes_to_read = |
187 std::min(static_cast<size_t>(*num_bytes), current_num_bytes_); | 196 std::min(static_cast<size_t>(*num_bytes), current_num_bytes_); |
188 if (num_bytes_to_read == 0) { | 197 if (num_bytes_to_read == 0) { |
189 return producer_open_no_lock() ? MOJO_RESULT_SHOULD_WAIT : | 198 return producer_open_no_lock() ? MOJO_RESULT_SHOULD_WAIT : |
190 MOJO_RESULT_FAILED_PRECONDITION; | 199 MOJO_RESULT_FAILED_PRECONDITION; |
191 } | 200 } |
192 | 201 |
193 // The amount we can read in our first |memcpy()|. | 202 // The amount we can read in our first |memcpy()|. |
194 size_t num_bytes_to_read_first = | 203 size_t num_bytes_to_read_first = |
(...skipping 18 matching lines...) Expand all Loading... |
213 | 222 |
214 *num_bytes = static_cast<uint32_t>(num_bytes_to_read); | 223 *num_bytes = static_cast<uint32_t>(num_bytes_to_read); |
215 return MOJO_RESULT_OK; | 224 return MOJO_RESULT_OK; |
216 } | 225 } |
217 | 226 |
218 MojoResult LocalDataPipe::ConsumerDiscardDataImplNoLock(uint32_t* num_bytes, | 227 MojoResult LocalDataPipe::ConsumerDiscardDataImplNoLock(uint32_t* num_bytes, |
219 bool all_or_none) { | 228 bool all_or_none) { |
220 DCHECK_EQ(*num_bytes % element_num_bytes(), 0u); | 229 DCHECK_EQ(*num_bytes % element_num_bytes(), 0u); |
221 DCHECK_GT(*num_bytes, 0u); | 230 DCHECK_GT(*num_bytes, 0u); |
222 | 231 |
223 // TODO(vtl): Think about the error code in this case. | 232 if (all_or_none && *num_bytes > current_num_bytes_) { |
224 if (all_or_none && *num_bytes > current_num_bytes_) | 233 // Don't return "should wait" since you can't wait for a specified amount of |
225 return MOJO_RESULT_OUT_OF_RANGE; | 234 // data. |
| 235 return producer_open_no_lock() ? MOJO_RESULT_OUT_OF_RANGE : |
| 236 MOJO_RESULT_FAILED_PRECONDITION; |
| 237 } |
226 | 238 |
227 // Be consistent with other operations; error if no data available. | 239 // Be consistent with other operations; error if no data available. |
228 if (current_num_bytes_ == 0) { | 240 if (current_num_bytes_ == 0) { |
229 return producer_open_no_lock() ? MOJO_RESULT_SHOULD_WAIT : | 241 return producer_open_no_lock() ? MOJO_RESULT_SHOULD_WAIT : |
230 MOJO_RESULT_FAILED_PRECONDITION; | 242 MOJO_RESULT_FAILED_PRECONDITION; |
231 } | 243 } |
232 | 244 |
233 bool was_full = (current_num_bytes_ == capacity_num_bytes()); | 245 bool was_full = (current_num_bytes_ == capacity_num_bytes()); |
234 | 246 |
235 size_t num_bytes_to_discard = | 247 size_t num_bytes_to_discard = |
(...skipping 12 matching lines...) Expand all Loading... |
248 // Note: This cast is safe, since the capacity fits into a |uint32_t|. | 260 // Note: This cast is safe, since the capacity fits into a |uint32_t|. |
249 *num_bytes = static_cast<uint32_t>(current_num_bytes_); | 261 *num_bytes = static_cast<uint32_t>(current_num_bytes_); |
250 return MOJO_RESULT_OK; | 262 return MOJO_RESULT_OK; |
251 } | 263 } |
252 | 264 |
253 MojoResult LocalDataPipe::ConsumerBeginReadDataImplNoLock( | 265 MojoResult LocalDataPipe::ConsumerBeginReadDataImplNoLock( |
254 const void** buffer, | 266 const void** buffer, |
255 uint32_t* buffer_num_bytes, | 267 uint32_t* buffer_num_bytes, |
256 bool all_or_none) { | 268 bool all_or_none) { |
257 size_t max_num_bytes_to_read = GetMaxNumBytesToReadNoLock(); | 269 size_t max_num_bytes_to_read = GetMaxNumBytesToReadNoLock(); |
258 // TODO(vtl): Consider this return value. | 270 if (all_or_none && *buffer_num_bytes > max_num_bytes_to_read) { |
259 if (all_or_none && *buffer_num_bytes > max_num_bytes_to_read) | 271 // Don't return "should wait" since you can't wait for a specified amount of |
| 272 // data. |
260 return MOJO_RESULT_OUT_OF_RANGE; | 273 return MOJO_RESULT_OUT_OF_RANGE; |
| 274 } |
261 | 275 |
262 // Don't go into a two-phase read if there's no data. | 276 // Don't go into a two-phase read if there's no data. |
263 if (max_num_bytes_to_read == 0) { | 277 if (max_num_bytes_to_read == 0) { |
264 return producer_open_no_lock() ? MOJO_RESULT_SHOULD_WAIT : | 278 return producer_open_no_lock() ? MOJO_RESULT_SHOULD_WAIT : |
265 MOJO_RESULT_FAILED_PRECONDITION; | 279 MOJO_RESULT_FAILED_PRECONDITION; |
266 } | 280 } |
267 | 281 |
268 *buffer = buffer_.get() + start_index_; | 282 *buffer = buffer_.get() + start_index_; |
269 *buffer_num_bytes = static_cast<uint32_t>(max_num_bytes_to_read); | 283 *buffer_num_bytes = static_cast<uint32_t>(max_num_bytes_to_read); |
270 set_consumer_two_phase_max_num_bytes_read_no_lock( | 284 set_consumer_two_phase_max_num_bytes_read_no_lock( |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
340 } | 354 } |
341 | 355 |
342 size_t LocalDataPipe::GetMaxNumBytesToReadNoLock() { | 356 size_t LocalDataPipe::GetMaxNumBytesToReadNoLock() { |
343 if (start_index_ + current_num_bytes_ > capacity_num_bytes()) | 357 if (start_index_ + current_num_bytes_ > capacity_num_bytes()) |
344 return capacity_num_bytes() - start_index_; | 358 return capacity_num_bytes() - start_index_; |
345 return current_num_bytes_; | 359 return current_num_bytes_; |
346 } | 360 } |
347 | 361 |
348 } // namespace system | 362 } // namespace system |
349 } // namespace mojo | 363 } // namespace mojo |
OLD | NEW |