| 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 |