diff options
-rw-r--r-- | mojo/system/core.cc | 223 | ||||
-rw-r--r-- | mojo/system/core.h | 62 | ||||
-rw-r--r-- | mojo/system/core_test_base.cc | 12 | ||||
-rw-r--r-- | mojo/system/core_unittest.cc | 423 | ||||
-rw-r--r-- | mojo/system/entrypoints.cc | 77 | ||||
-rw-r--r-- | mojo/system/mapping_table.cc | 5 | ||||
-rw-r--r-- | mojo/system/mapping_table.h | 2 | ||||
-rw-r--r-- | mojo/system/memory.cc | 36 | ||||
-rw-r--r-- | mojo/system/memory.h | 270 |
9 files changed, 790 insertions, 320 deletions
diff --git a/mojo/system/core.cc b/mojo/system/core.cc index d72198f..49c90db 100644 --- a/mojo/system/core.cc +++ b/mojo/system/core.cc @@ -123,34 +123,31 @@ MojoResult Core::Wait(MojoHandle handle, return WaitManyInternal(&handle, &signals, 1, deadline); } -MojoResult Core::WaitMany(const MojoHandle* handles, - const MojoHandleSignals* signals, +MojoResult Core::WaitMany(UserPointer<const MojoHandle> handles, + UserPointer<const MojoHandleSignals> signals, uint32_t num_handles, MojoDeadline deadline) { - if (!VerifyUserPointerWithCount<MojoHandle>(handles, num_handles)) - return MOJO_RESULT_INVALID_ARGUMENT; - if (!VerifyUserPointerWithCount<MojoHandleSignals>(signals, num_handles)) - return MOJO_RESULT_INVALID_ARGUMENT; if (num_handles < 1) return MOJO_RESULT_INVALID_ARGUMENT; if (num_handles > kMaxWaitManyNumHandles) return MOJO_RESULT_RESOURCE_EXHAUSTED; - return WaitManyInternal(handles, signals, num_handles, deadline); + UserPointer<const MojoHandle>::Reader handles_reader(handles, num_handles); + UserPointer<const MojoHandleSignals>::Reader signals_reader(signals, + num_handles); + return WaitManyInternal(handles_reader.GetPointer(), + signals_reader.GetPointer(), num_handles, deadline); } -MojoResult Core::CreateMessagePipe(const MojoCreateMessagePipeOptions* options, - MojoHandle* message_pipe_handle0, - MojoHandle* message_pipe_handle1) { +MojoResult Core::CreateMessagePipe( + UserPointer<const MojoCreateMessagePipeOptions> options, + UserPointer<MojoHandle> message_pipe_handle0, + UserPointer<MojoHandle> message_pipe_handle1) { MojoCreateMessagePipeOptions validated_options = {}; // This will verify the |options| pointer. MojoResult result = MessagePipeDispatcher::ValidateCreateOptions( - options, &validated_options); + options.GetPointerUnsafe(), &validated_options); if (result != MOJO_RESULT_OK) return result; - if (!VerifyUserPointer<MojoHandle>(message_pipe_handle0)) - return MOJO_RESULT_INVALID_ARGUMENT; - if (!VerifyUserPointer<MojoHandle>(message_pipe_handle1)) - return MOJO_RESULT_INVALID_ARGUMENT; scoped_refptr<MessagePipeDispatcher> dispatcher0( new MessagePipeDispatcher(validated_options)); @@ -174,8 +171,8 @@ MojoResult Core::CreateMessagePipe(const MojoCreateMessagePipeOptions* options, dispatcher0->Init(message_pipe, 0); dispatcher1->Init(message_pipe, 1); - *message_pipe_handle0 = handle_pair.first; - *message_pipe_handle1 = handle_pair.second; + message_pipe_handle0.Put(handle_pair.first); + message_pipe_handle1.Put(handle_pair.second); return MOJO_RESULT_OK; } @@ -187,9 +184,9 @@ MojoResult Core::CreateMessagePipe(const MojoCreateMessagePipeOptions* options, // after the the message has been received and a new handle created (and // possibly even after calls have been made on the new handle). MojoResult Core::WriteMessage(MojoHandle message_pipe_handle, - const void* bytes, + UserPointer<const void> bytes, uint32_t num_bytes, - const MojoHandle* handles, + UserPointer<const MojoHandle> handles, uint32_t num_handles, MojoWriteMessageFlags flags) { scoped_refptr<Dispatcher> dispatcher(GetDispatcher(message_pipe_handle)); @@ -197,8 +194,10 @@ MojoResult Core::WriteMessage(MojoHandle message_pipe_handle, return MOJO_RESULT_INVALID_ARGUMENT; // Easy case: not sending any handles. - if (num_handles == 0) - return dispatcher->WriteMessage(bytes, num_bytes, NULL, flags); + if (num_handles == 0) { + return dispatcher->WriteMessage(bytes.GetPointerUnsafe(), num_bytes, NULL, + flags); + } // We have to handle |handles| here, since we have to mark them busy in the // global handle table. We can't delegate this to the dispatcher, since the @@ -208,11 +207,11 @@ MojoResult Core::WriteMessage(MojoHandle message_pipe_handle, // validity, even for dispatchers that don't support |WriteMessage()| and will // simply return failure unconditionally. It also breaks the usual // left-to-right verification order of arguments.) - if (!VerifyUserPointerWithCount<MojoHandle>(handles, num_handles)) - return MOJO_RESULT_INVALID_ARGUMENT; if (num_handles > kMaxMessageNumHandles) return MOJO_RESULT_RESOURCE_EXHAUSTED; + UserPointer<const MojoHandle>::Reader handles_reader(handles, num_handles); + // We'll need to hold on to the dispatchers so that we can pass them on to // |WriteMessage()| and also so that we can unlock their locks afterwards // without accessing the handle table. These can be dumb pointers, since their @@ -226,13 +225,14 @@ MojoResult Core::WriteMessage(MojoHandle message_pipe_handle, { base::AutoLock locker(handle_table_lock_); MojoResult result = handle_table_.MarkBusyAndStartTransport( - message_pipe_handle, handles, num_handles, &transports); + message_pipe_handle, handles_reader.GetPointer(), num_handles, + &transports); if (result != MOJO_RESULT_OK) return result; } - MojoResult rv = dispatcher->WriteMessage(bytes, num_bytes, &transports, - flags); + MojoResult rv = dispatcher->WriteMessage(bytes.GetPointerUnsafe(), num_bytes, + &transports, flags); // We need to release the dispatcher locks before we take the handle table // lock. @@ -241,77 +241,84 @@ MojoResult Core::WriteMessage(MojoHandle message_pipe_handle, { base::AutoLock locker(handle_table_lock_); - if (rv == MOJO_RESULT_OK) - handle_table_.RemoveBusyHandles(handles, num_handles); - else - handle_table_.RestoreBusyHandles(handles, num_handles); + if (rv == MOJO_RESULT_OK) { + handle_table_.RemoveBusyHandles(handles_reader.GetPointer(), num_handles); + } else { + handle_table_.RestoreBusyHandles(handles_reader.GetPointer(), + num_handles); + } } return rv; } MojoResult Core::ReadMessage(MojoHandle message_pipe_handle, - void* bytes, - uint32_t* num_bytes, - MojoHandle* handles, - uint32_t* num_handles, + UserPointer<void> bytes, + UserPointer<uint32_t> num_bytes, + UserPointer<MojoHandle> handles, + UserPointer<uint32_t> num_handles, MojoReadMessageFlags flags) { scoped_refptr<Dispatcher> dispatcher(GetDispatcher(message_pipe_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; - if (num_handles) { - if (!VerifyUserPointer<uint32_t>(num_handles)) - return MOJO_RESULT_INVALID_ARGUMENT; - if (!VerifyUserPointerWithCount<MojoHandle>(handles, *num_handles)) - return MOJO_RESULT_INVALID_ARGUMENT; - } - - // Easy case: won't receive any handles. - if (!num_handles || *num_handles == 0) - return dispatcher->ReadMessage(bytes, num_bytes, NULL, num_handles, flags); - - DispatcherVector dispatchers; - MojoResult rv = dispatcher->ReadMessage(bytes, num_bytes, - &dispatchers, num_handles, - flags); - if (!dispatchers.empty()) { - DCHECK_EQ(rv, MOJO_RESULT_OK); - DCHECK(num_handles); - DCHECK_LE(dispatchers.size(), static_cast<size_t>(*num_handles)); - - bool success; - { - base::AutoLock locker(handle_table_lock_); - success = handle_table_.AddDispatcherVector(dispatchers, handles); - } - if (!success) { - LOG(ERROR) << "Received message with " << dispatchers.size() - << " handles, but handle table full"; - // Close dispatchers (outside the lock). - for (size_t i = 0; i < dispatchers.size(); i++) { - if (dispatchers[i]) - dispatchers[i]->Close(); + uint32_t num_handles_value = num_handles.IsNull() ? 0 : num_handles.Get(); + + MojoResult rv; + if (num_handles_value == 0) { + // Easy case: won't receive any handles. + rv = dispatcher->ReadMessage(bytes.GetPointerUnsafe(), + num_bytes.GetPointerUnsafe(), NULL, + &num_handles_value, flags); + } else { + DispatcherVector dispatchers; + rv = dispatcher->ReadMessage(bytes.GetPointerUnsafe(), + num_bytes.GetPointerUnsafe(), &dispatchers, + &num_handles_value, flags); + if (!dispatchers.empty()) { + DCHECK_EQ(rv, MOJO_RESULT_OK); + DCHECK(!num_handles.IsNull()); + DCHECK_LE(dispatchers.size(), static_cast<size_t>(num_handles_value)); + + bool success; + UserPointer<MojoHandle>::Writer handles_writer(handles, + dispatchers.size()); + { + base::AutoLock locker(handle_table_lock_); + success = handle_table_.AddDispatcherVector( + dispatchers, handles_writer.GetPointer()); + } + if (success) { + handles_writer.Commit(); + } else { + LOG(ERROR) << "Received message with " << dispatchers.size() + << " handles, but handle table full"; + // Close dispatchers (outside the lock). + for (size_t i = 0; i < dispatchers.size(); i++) { + if (dispatchers[i]) + dispatchers[i]->Close(); + } + if (rv == MOJO_RESULT_OK) + rv = MOJO_RESULT_RESOURCE_EXHAUSTED; } } } + if (!num_handles.IsNull()) + num_handles.Put(num_handles_value); return rv; } -MojoResult Core::CreateDataPipe(const MojoCreateDataPipeOptions* options, - MojoHandle* data_pipe_producer_handle, - MojoHandle* data_pipe_consumer_handle) { +MojoResult Core::CreateDataPipe( + UserPointer<const MojoCreateDataPipeOptions> options, + UserPointer<MojoHandle> data_pipe_producer_handle, + UserPointer<MojoHandle> data_pipe_consumer_handle) { MojoCreateDataPipeOptions validated_options = {}; // This will verify the |options| pointer. - MojoResult result = DataPipe::ValidateCreateOptions(options, - &validated_options); + MojoResult result = DataPipe::ValidateCreateOptions( + options.GetPointerUnsafe(), &validated_options); if (result != MOJO_RESULT_OK) return result; - if (!VerifyUserPointer<MojoHandle>(data_pipe_producer_handle)) - return MOJO_RESULT_INVALID_ARGUMENT; - if (!VerifyUserPointer<MojoHandle>(data_pipe_consumer_handle)) - return MOJO_RESULT_INVALID_ARGUMENT; scoped_refptr<DataPipeProducerDispatcher> producer_dispatcher( new DataPipeProducerDispatcher()); @@ -337,33 +344,35 @@ MojoResult Core::CreateDataPipe(const MojoCreateDataPipeOptions* options, producer_dispatcher->Init(data_pipe); consumer_dispatcher->Init(data_pipe); - *data_pipe_producer_handle = handle_pair.first; - *data_pipe_consumer_handle = handle_pair.second; + data_pipe_producer_handle.Put(handle_pair.first); + data_pipe_consumer_handle.Put(handle_pair.second); return MOJO_RESULT_OK; } MojoResult Core::WriteData(MojoHandle data_pipe_producer_handle, - const void* elements, - uint32_t* num_bytes, + UserPointer<const void> elements, + UserPointer<uint32_t> num_bytes, MojoWriteDataFlags flags) { scoped_refptr<Dispatcher> dispatcher( GetDispatcher(data_pipe_producer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; - return dispatcher->WriteData(elements, num_bytes, flags); + return dispatcher->WriteData(elements.GetPointerUnsafe(), + num_bytes.GetPointerUnsafe(), flags); } MojoResult Core::BeginWriteData(MojoHandle data_pipe_producer_handle, - void** buffer, - uint32_t* buffer_num_bytes, + UserPointer<void*> buffer, + UserPointer<uint32_t> buffer_num_bytes, MojoWriteDataFlags flags) { scoped_refptr<Dispatcher> dispatcher( GetDispatcher(data_pipe_producer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; - return dispatcher->BeginWriteData(buffer, buffer_num_bytes, flags); + return dispatcher->BeginWriteData(buffer.GetPointerUnsafe(), + buffer_num_bytes.GetPointerUnsafe(), flags); } MojoResult Core::EndWriteData(MojoHandle data_pipe_producer_handle, @@ -377,27 +386,29 @@ MojoResult Core::EndWriteData(MojoHandle data_pipe_producer_handle, } MojoResult Core::ReadData(MojoHandle data_pipe_consumer_handle, - void* elements, - uint32_t* num_bytes, + UserPointer<void> elements, + UserPointer<uint32_t> num_bytes, MojoReadDataFlags flags) { scoped_refptr<Dispatcher> dispatcher( GetDispatcher(data_pipe_consumer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; - return dispatcher->ReadData(elements, num_bytes, flags); + return dispatcher->ReadData(elements.GetPointerUnsafe(), + num_bytes.GetPointerUnsafe(), flags); } MojoResult Core::BeginReadData(MojoHandle data_pipe_consumer_handle, - const void** buffer, - uint32_t* buffer_num_bytes, + UserPointer<const void*> buffer, + UserPointer<uint32_t> buffer_num_bytes, MojoReadDataFlags flags) { scoped_refptr<Dispatcher> dispatcher( GetDispatcher(data_pipe_consumer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; - return dispatcher->BeginReadData(buffer, buffer_num_bytes, flags); + return dispatcher->BeginReadData(buffer.GetPointerUnsafe(), + buffer_num_bytes.GetPointerUnsafe(), flags); } MojoResult Core::EndReadData(MojoHandle data_pipe_consumer_handle, @@ -411,18 +422,16 @@ MojoResult Core::EndReadData(MojoHandle data_pipe_consumer_handle, } MojoResult Core::CreateSharedBuffer( - const MojoCreateSharedBufferOptions* options, + UserPointer<const MojoCreateSharedBufferOptions> options, uint64_t num_bytes, - MojoHandle* shared_buffer_handle) { + UserPointer<MojoHandle> shared_buffer_handle) { MojoCreateSharedBufferOptions validated_options = {}; // This will verify the |options| pointer. MojoResult result = - SharedBufferDispatcher::ValidateCreateOptions(options, + SharedBufferDispatcher::ValidateCreateOptions(options.GetPointerUnsafe(), &validated_options); if (result != MOJO_RESULT_OK) return result; - if (!VerifyUserPointer<MojoHandle>(shared_buffer_handle)) - return MOJO_RESULT_INVALID_ARGUMENT; scoped_refptr<SharedBufferDispatcher> dispatcher; result = SharedBufferDispatcher::Create(validated_options, num_bytes, @@ -439,25 +448,22 @@ MojoResult Core::CreateSharedBuffer( return MOJO_RESULT_RESOURCE_EXHAUSTED; } - *shared_buffer_handle = h; + shared_buffer_handle.Put(h); return MOJO_RESULT_OK; } MojoResult Core::DuplicateBufferHandle( MojoHandle buffer_handle, - const MojoDuplicateBufferHandleOptions* options, - MojoHandle* new_buffer_handle) { + UserPointer<const MojoDuplicateBufferHandleOptions> options, + UserPointer<MojoHandle> new_buffer_handle) { scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; // Don't verify |options| here; that's the dispatcher's job. - if (!VerifyUserPointer<MojoHandle>(new_buffer_handle)) - return MOJO_RESULT_INVALID_ARGUMENT; - scoped_refptr<Dispatcher> new_dispatcher; - MojoResult result = dispatcher->DuplicateBufferHandle(options, - &new_dispatcher); + MojoResult result = dispatcher->DuplicateBufferHandle( + options.GetPointerUnsafe(), &new_dispatcher); if (result != MOJO_RESULT_OK) return result; @@ -468,22 +474,19 @@ MojoResult Core::DuplicateBufferHandle( return MOJO_RESULT_RESOURCE_EXHAUSTED; } - *new_buffer_handle = new_handle; + new_buffer_handle.Put(new_handle); return MOJO_RESULT_OK; } MojoResult Core::MapBuffer(MojoHandle buffer_handle, uint64_t offset, uint64_t num_bytes, - void** buffer, + UserPointer<void*> buffer, MojoMapBufferFlags flags) { scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; - if (!VerifyUserPointerWithCount<void*>(buffer, 1)) - return MOJO_RESULT_INVALID_ARGUMENT; - scoped_ptr<RawSharedBufferMapping> mapping; MojoResult result = dispatcher->MapBuffer(offset, num_bytes, flags, &mapping); if (result != MOJO_RESULT_OK) @@ -498,13 +501,13 @@ MojoResult Core::MapBuffer(MojoHandle buffer_handle, if (result != MOJO_RESULT_OK) return result; - *buffer = address; + buffer.Put(address); return MOJO_RESULT_OK; } -MojoResult Core::UnmapBuffer(void* buffer) { +MojoResult Core::UnmapBuffer(UserPointerValue<void> buffer) { base::AutoLock locker(mapping_table_lock_); - return mapping_table_.RemoveMapping(buffer); + return mapping_table_.RemoveMapping(buffer.GetValue()); } // Note: We allow |handles| to repeat the same handle multiple times, since diff --git a/mojo/system/core.h b/mojo/system/core.h index a0bc293..ba811f8 100644 --- a/mojo/system/core.h +++ b/mojo/system/core.h @@ -15,6 +15,7 @@ #include "mojo/public/c/system/types.h" #include "mojo/system/handle_table.h" #include "mojo/system/mapping_table.h" +#include "mojo/system/memory.h" #include "mojo/system/system_impl_export.h" namespace mojo { @@ -44,61 +45,64 @@ class MOJO_SYSTEM_IMPL_EXPORT Core { MojoResult Wait(MojoHandle handle, MojoHandleSignals signals, MojoDeadline deadline); - MojoResult WaitMany(const MojoHandle* handles, - const MojoHandleSignals* signals, + MojoResult WaitMany(UserPointer<const MojoHandle> handles, + UserPointer<const MojoHandleSignals> signals, uint32_t num_handles, MojoDeadline deadline); - MojoResult CreateMessagePipe(const MojoCreateMessagePipeOptions* options, - MojoHandle* message_pipe_handle0, - MojoHandle* message_pipe_handle1); + MojoResult CreateMessagePipe( + UserPointer<const MojoCreateMessagePipeOptions> options, + UserPointer<MojoHandle> message_pipe_handle0, + UserPointer<MojoHandle> message_pipe_handle1); MojoResult WriteMessage(MojoHandle message_pipe_handle, - const void* bytes, + UserPointer<const void> bytes, uint32_t num_bytes, - const MojoHandle* handles, + UserPointer<const MojoHandle> handles, uint32_t num_handles, MojoWriteMessageFlags flags); MojoResult ReadMessage(MojoHandle message_pipe_handle, - void* bytes, - uint32_t* num_bytes, - MojoHandle* handles, - uint32_t* num_handles, + UserPointer<void> bytes, + UserPointer<uint32_t> num_bytes, + UserPointer<MojoHandle> handles, + UserPointer<uint32_t> num_handles, MojoReadMessageFlags flags); - MojoResult CreateDataPipe(const MojoCreateDataPipeOptions* options, - MojoHandle* data_pipe_producer_handle, - MojoHandle* data_pipe_consumer_handle); + MojoResult CreateDataPipe( + UserPointer<const MojoCreateDataPipeOptions> options, + UserPointer<MojoHandle> data_pipe_producer_handle, + UserPointer<MojoHandle> data_pipe_consumer_handle); MojoResult WriteData(MojoHandle data_pipe_producer_handle, - const void* elements, - uint32_t* num_bytes, + UserPointer<const void> elements, + UserPointer<uint32_t> num_bytes, MojoWriteDataFlags flags); MojoResult BeginWriteData(MojoHandle data_pipe_producer_handle, - void** buffer, - uint32_t* buffer_num_bytes, + UserPointer<void*> buffer, + UserPointer<uint32_t> buffer_num_bytes, MojoWriteDataFlags flags); MojoResult EndWriteData(MojoHandle data_pipe_producer_handle, uint32_t num_bytes_written); MojoResult ReadData(MojoHandle data_pipe_consumer_handle, - void* elements, - uint32_t* num_bytes, + UserPointer<void> elements, + UserPointer<uint32_t> num_bytes, MojoReadDataFlags flags); MojoResult BeginReadData(MojoHandle data_pipe_consumer_handle, - const void** buffer, - uint32_t* buffer_num_bytes, + UserPointer<const void*> buffer, + UserPointer<uint32_t> buffer_num_bytes, MojoReadDataFlags flags); MojoResult EndReadData(MojoHandle data_pipe_consumer_handle, uint32_t num_bytes_read); - MojoResult CreateSharedBuffer(const MojoCreateSharedBufferOptions* options, - uint64_t num_bytes, - MojoHandle* shared_buffer_handle); + MojoResult CreateSharedBuffer( + UserPointer<const MojoCreateSharedBufferOptions> options, + uint64_t num_bytes, + UserPointer<MojoHandle> shared_buffer_handle); MojoResult DuplicateBufferHandle( MojoHandle buffer_handle, - const MojoDuplicateBufferHandleOptions* options, - MojoHandle* new_buffer_handle); + UserPointer<const MojoDuplicateBufferHandleOptions> options, + UserPointer<MojoHandle> new_buffer_handle); MojoResult MapBuffer(MojoHandle buffer_handle, uint64_t offset, uint64_t num_bytes, - void** buffer, + UserPointer<void*> buffer, MojoMapBufferFlags flags); - MojoResult UnmapBuffer(void* buffer); + MojoResult UnmapBuffer(UserPointerValue<void> buffer); private: friend bool internal::ShutdownCheckNoLeaks(Core*); diff --git a/mojo/system/core_test_base.cc b/mojo/system/core_test_base.cc index c91437c..c02b118 100644 --- a/mojo/system/core_test_base.cc +++ b/mojo/system/core_test_base.cc @@ -68,8 +68,8 @@ class MockDispatcher : public Dispatcher { virtual MojoResult ReadMessageImplNoLock( void* bytes, uint32_t* num_bytes, - DispatcherVector* /*dispatchers*/, - uint32_t* /*num_dispatchers*/, + DispatcherVector* dispatchers, + uint32_t* num_dispatchers, MojoReadMessageFlags /*flags*/) OVERRIDE { info_->IncrementReadMessageCallCount(); lock().AssertAcquired(); @@ -77,6 +77,14 @@ class MockDispatcher : public Dispatcher { if (num_bytes && !VerifyUserPointerWithSize<1>(bytes, *num_bytes)) return MOJO_RESULT_INVALID_ARGUMENT; + if (num_dispatchers) { + *num_dispatchers = 1; + if (dispatchers) { + // Okay to leave an invalid dispatcher. + dispatchers->resize(1); + } + } + return MOJO_RESULT_OK; } diff --git a/mojo/system/core_unittest.cc b/mojo/system/core_unittest.cc index af3d0c1..59ff1c8 100644 --- a/mojo/system/core_unittest.cc +++ b/mojo/system/core_unittest.cc @@ -38,38 +38,45 @@ TEST_F(CoreTest, Basic) { EXPECT_EQ(0u, info.GetWriteMessageCallCount()); EXPECT_EQ(MOJO_RESULT_OK, - core()->WriteMessage(h, NULL, 0, NULL, 0, + core()->WriteMessage(h, NullUserPointer(), 0, NullUserPointer(), 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(1u, info.GetWriteMessageCallCount()); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->WriteMessage(h, NULL, 1, NULL, 0, + core()->WriteMessage(h, NullUserPointer(), 1, NullUserPointer(), 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(2u, info.GetWriteMessageCallCount()); EXPECT_EQ(0u, info.GetReadMessageCallCount()); uint32_t num_bytes = 0; EXPECT_EQ(MOJO_RESULT_OK, - core()->ReadMessage(h, NULL, &num_bytes, NULL, NULL, + core()->ReadMessage(h, NullUserPointer(), + MakeUserPointer(&num_bytes), NullUserPointer(), + NullUserPointer(), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(1u, info.GetReadMessageCallCount()); num_bytes = 1; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->ReadMessage(h, NULL, &num_bytes, NULL, NULL, + core()->ReadMessage(h, NullUserPointer(), + MakeUserPointer(&num_bytes), NullUserPointer(), + NullUserPointer(), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(2u, info.GetReadMessageCallCount()); EXPECT_EQ(MOJO_RESULT_OK, - core()->ReadMessage(h, NULL, NULL, NULL, NULL, + core()->ReadMessage(h, NullUserPointer(), NullUserPointer(), + NullUserPointer(), NullUserPointer(), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(3u, info.GetReadMessageCallCount()); EXPECT_EQ(0u, info.GetWriteDataCallCount()); EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED, - core()->WriteData(h, NULL, NULL, MOJO_WRITE_DATA_FLAG_NONE)); + core()->WriteData(h, NullUserPointer(), NullUserPointer(), + MOJO_WRITE_DATA_FLAG_NONE)); EXPECT_EQ(1u, info.GetWriteDataCallCount()); EXPECT_EQ(0u, info.GetBeginWriteDataCallCount()); EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED, - core()->BeginWriteData(h, NULL, NULL, MOJO_WRITE_DATA_FLAG_NONE)); + core()->BeginWriteData(h, NullUserPointer(), NullUserPointer(), + MOJO_WRITE_DATA_FLAG_NONE)); EXPECT_EQ(1u, info.GetBeginWriteDataCallCount()); EXPECT_EQ(0u, info.GetEndWriteDataCallCount()); @@ -79,12 +86,14 @@ TEST_F(CoreTest, Basic) { EXPECT_EQ(0u, info.GetReadDataCallCount()); EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED, - core()->ReadData(h, NULL, NULL, MOJO_READ_DATA_FLAG_NONE)); + core()->ReadData(h, NullUserPointer(), NullUserPointer(), + MOJO_READ_DATA_FLAG_NONE)); EXPECT_EQ(1u, info.GetReadDataCallCount()); EXPECT_EQ(0u, info.GetBeginReadDataCallCount()); EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED, - core()->BeginReadData(h, NULL, NULL, MOJO_READ_DATA_FLAG_NONE)); + core()->BeginReadData(h, NullUserPointer(), NullUserPointer(), + MOJO_READ_DATA_FLAG_NONE)); EXPECT_EQ(1u, info.GetBeginReadDataCallCount()); EXPECT_EQ(0u, info.GetEndReadDataCallCount()); @@ -105,7 +114,9 @@ TEST_F(CoreTest, Basic) { EXPECT_EQ(3u, info.GetAddWaiterCallCount()); MojoHandleSignals handle_signals = ~MOJO_HANDLE_SIGNAL_NONE; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - core()->WaitMany(&h, &handle_signals, 1, MOJO_DEADLINE_INDEFINITE)); + core()->WaitMany(MakeUserPointer(&h), + MakeUserPointer(&handle_signals), 1, + MOJO_DEADLINE_INDEFINITE)); EXPECT_EQ(4u, info.GetAddWaiterCallCount()); EXPECT_EQ(0u, info.GetDtorCallCount()); @@ -152,81 +163,78 @@ TEST_F(CoreTest, InvalidArguments) { MojoHandleSignals signals[2] = {~MOJO_HANDLE_SIGNAL_NONE, ~MOJO_HANDLE_SIGNAL_NONE}; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->WaitMany(handles, signals, 0, MOJO_DEADLINE_INDEFINITE)); - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->WaitMany(NULL, signals, 0, MOJO_DEADLINE_INDEFINITE)); + core()->WaitMany(MakeUserPointer(handles), + MakeUserPointer(signals), 0, + MOJO_DEADLINE_INDEFINITE)); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->WaitMany(handles, NULL, 0, MOJO_DEADLINE_INDEFINITE)); - - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->WaitMany(NULL, signals, 1, MOJO_DEADLINE_INDEFINITE)); + core()->WaitMany(NullUserPointer(), MakeUserPointer(signals), 0, + MOJO_DEADLINE_INDEFINITE)); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->WaitMany(handles, NULL, 1, MOJO_DEADLINE_INDEFINITE)); + core()->WaitMany(MakeUserPointer(handles), NullUserPointer(), 0, + MOJO_DEADLINE_INDEFINITE)); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->WaitMany(handles, signals, 1, MOJO_DEADLINE_INDEFINITE)); + core()->WaitMany(MakeUserPointer(handles), + MakeUserPointer(signals), 1, + MOJO_DEADLINE_INDEFINITE)); MockHandleInfo info[2]; handles[0] = CreateMockHandle(&info[0]); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - core()->WaitMany(handles, signals, 1, MOJO_DEADLINE_INDEFINITE)); + core()->WaitMany(MakeUserPointer(handles), + MakeUserPointer(signals), 1, + MOJO_DEADLINE_INDEFINITE)); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->WaitMany(handles, signals, 2, MOJO_DEADLINE_INDEFINITE)); + core()->WaitMany(MakeUserPointer(handles), + MakeUserPointer(signals), 2, + MOJO_DEADLINE_INDEFINITE)); handles[1] = handles[0] + 1; // Invalid handle. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->WaitMany(handles, signals, 2, MOJO_DEADLINE_INDEFINITE)); + core()->WaitMany(MakeUserPointer(handles), + MakeUserPointer(signals), 2, + MOJO_DEADLINE_INDEFINITE)); handles[1] = CreateMockHandle(&info[1]); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - core()->WaitMany(handles, signals, 2, MOJO_DEADLINE_INDEFINITE)); + core()->WaitMany(MakeUserPointer(handles), + MakeUserPointer(signals), 2, + MOJO_DEADLINE_INDEFINITE)); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(handles[0])); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(handles[1])); } - // |CreateMessagePipe()|: - { - MojoHandle h; - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->CreateMessagePipe(NULL, NULL, NULL)); - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->CreateMessagePipe(NULL, &h, NULL)); - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->CreateMessagePipe(NULL, NULL, &h)); - } + // |CreateMessagePipe()|: Nothing to check (apart from things that cause + // death). // |WriteMessage()|: // Only check arguments checked by |Core|, namely |handle|, |handles|, and // |num_handles|. { EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->WriteMessage(MOJO_HANDLE_INVALID, NULL, 0, NULL, 0, + core()->WriteMessage(MOJO_HANDLE_INVALID, NullUserPointer(), 0, + NullUserPointer(), 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); MockHandleInfo info; MojoHandle h = CreateMockHandle(&info); MojoHandle handles[2] = {MOJO_HANDLE_INVALID, MOJO_HANDLE_INVALID}; - // Null |handles| with nonzero |num_handles|. - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->WriteMessage(h, NULL, 0, NULL, 1, - MOJO_WRITE_MESSAGE_FLAG_NONE)); - // Checked by |Core|, shouldn't go through to the dispatcher. - EXPECT_EQ(0u, info.GetWriteMessageCallCount()); - // Huge handle count (implausibly big on some systems -- more than can be // stored in a 32-bit address space). // Note: This may return either |MOJO_RESULT_INVALID_ARGUMENT| or // |MOJO_RESULT_RESOURCE_EXHAUSTED|, depending on whether it's plausible or // not. EXPECT_NE(MOJO_RESULT_OK, - core()->WriteMessage(h, NULL, 0, handles, + core()->WriteMessage(h, NullUserPointer(), 0, + MakeUserPointer(handles), std::numeric_limits<uint32_t>::max(), MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(0u, info.GetWriteMessageCallCount()); // Huge handle count (plausibly big). EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED, - core()->WriteMessage(h, NULL, 0, handles, + core()->WriteMessage(h, NullUserPointer(), 0, + MakeUserPointer(handles), std::numeric_limits<uint32_t>::max() / sizeof(handles[0]), MOJO_WRITE_MESSAGE_FLAG_NONE)); @@ -234,20 +242,23 @@ TEST_F(CoreTest, InvalidArguments) { // Invalid handle in |handles|. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->WriteMessage(h, NULL, 0, handles, 1, + core()->WriteMessage(h, NullUserPointer(), 0, + MakeUserPointer(handles), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(0u, info.GetWriteMessageCallCount()); // Two invalid handles in |handles|. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->WriteMessage(h, NULL, 0, handles, 2, + core()->WriteMessage(h, NullUserPointer(), 0, + MakeUserPointer(handles), 2, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(0u, info.GetWriteMessageCallCount()); // Can't send a handle over itself. handles[0] = h; EXPECT_EQ(MOJO_RESULT_BUSY, - core()->WriteMessage(h, NULL, 0, handles, 1, + core()->WriteMessage(h, NullUserPointer(), 0, + MakeUserPointer(handles), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(0u, info.GetWriteMessageCallCount()); @@ -257,27 +268,31 @@ TEST_F(CoreTest, InvalidArguments) { // This is "okay", but |MockDispatcher| doesn't implement it. handles[0] = h2; EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED, - core()->WriteMessage(h, NULL, 0, handles, 1, + core()->WriteMessage(h, NullUserPointer(), 0, + MakeUserPointer(handles), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(1u, info.GetWriteMessageCallCount()); // One of the |handles| is still invalid. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->WriteMessage(h, NULL, 0, handles, 2, + core()->WriteMessage(h, NullUserPointer(), 0, + MakeUserPointer(handles), 2, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(1u, info.GetWriteMessageCallCount()); // One of the |handles| is the same as |handle|. handles[1] = h; EXPECT_EQ(MOJO_RESULT_BUSY, - core()->WriteMessage(h, NULL, 0, handles, 2, + core()->WriteMessage(h, NullUserPointer(), 0, + MakeUserPointer(handles), 2, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(1u, info.GetWriteMessageCallCount()); // Can't send a handle twice in the same message. handles[1] = h2; EXPECT_EQ(MOJO_RESULT_BUSY, - core()->WriteMessage(h, NULL, 0, handles, 2, + core()->WriteMessage(h, NullUserPointer(), 0, + MakeUserPointer(handles), 2, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(1u, info.GetWriteMessageCallCount()); @@ -293,23 +308,20 @@ TEST_F(CoreTest, InvalidArguments) { // |num_handles|. { EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->ReadMessage(MOJO_HANDLE_INVALID, NULL, NULL, NULL, NULL, + core()->ReadMessage(MOJO_HANDLE_INVALID, NullUserPointer(), + NullUserPointer(), NullUserPointer(), + NullUserPointer(), MOJO_READ_MESSAGE_FLAG_NONE)); MockHandleInfo info; MojoHandle h = CreateMockHandle(&info); - uint32_t handle_count = 1; - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->ReadMessage(h, NULL, NULL, NULL, &handle_count, - MOJO_READ_MESSAGE_FLAG_NONE)); - // Checked by |Core|, shouldn't go through to the dispatcher. - EXPECT_EQ(0u, info.GetReadMessageCallCount()); - // Okay. - handle_count = 0; + uint32_t handle_count = 0; EXPECT_EQ(MOJO_RESULT_OK, - core()->ReadMessage(h, NULL, NULL, NULL, &handle_count, + core()->ReadMessage(h, NullUserPointer(), NullUserPointer(), + NullUserPointer(), + MakeUserPointer(&handle_count), MOJO_READ_MESSAGE_FLAG_NONE)); // Checked by |Core|, shouldn't go through to the dispatcher. EXPECT_EQ(1u, info.GetReadMessageCallCount()); @@ -318,6 +330,82 @@ TEST_F(CoreTest, InvalidArguments) { } } +// These test invalid arguments that should cause death if we're being paranoid +// about checking arguments (which we would want to do if, e.g., we were in a +// true "kernel" situation, but we might not want to do otherwise for +// performance reasons). Probably blatant errors like passing in null pointers +// (for required pointer arguments) will still cause death, but perhaps not +// predictably. +TEST_F(CoreTest, InvalidArgumentsDeath) { + const char kMemoryCheckFailedRegex[] = "Check failed"; + + // |WaitMany()|: + { + MojoHandle handles[2] = {MOJO_HANDLE_INVALID, MOJO_HANDLE_INVALID}; + MojoHandleSignals signals[2] = {~MOJO_HANDLE_SIGNAL_NONE, + ~MOJO_HANDLE_SIGNAL_NONE}; + EXPECT_DEATH_IF_SUPPORTED( + core()->WaitMany(NullUserPointer(), MakeUserPointer(signals), 1, + MOJO_DEADLINE_INDEFINITE), + kMemoryCheckFailedRegex); + EXPECT_DEATH_IF_SUPPORTED( + core()->WaitMany(MakeUserPointer(handles), NullUserPointer(), 1, + MOJO_DEADLINE_INDEFINITE), + kMemoryCheckFailedRegex); + } + + // |CreateMessagePipe()|: + { + MojoHandle h; + EXPECT_DEATH_IF_SUPPORTED( + core()->CreateMessagePipe(NullUserPointer(), NullUserPointer(), + NullUserPointer()), + kMemoryCheckFailedRegex); + EXPECT_DEATH_IF_SUPPORTED( + core()->CreateMessagePipe(NullUserPointer(), MakeUserPointer(&h), + NullUserPointer()), + kMemoryCheckFailedRegex); + EXPECT_DEATH_IF_SUPPORTED( + core()->CreateMessagePipe(NullUserPointer(), NullUserPointer(), + MakeUserPointer(&h)), + kMemoryCheckFailedRegex); + } + + // |WriteMessage()|: + // Only check arguments checked by |Core|, namely |handle|, |handles|, and + // |num_handles|. + { + MockHandleInfo info; + MojoHandle h = CreateMockHandle(&info); + + // Null |handles| with nonzero |num_handles|. + EXPECT_DEATH_IF_SUPPORTED( + core()->WriteMessage(h, NullUserPointer(), 0, NullUserPointer(), + 1, MOJO_WRITE_MESSAGE_FLAG_NONE), + kMemoryCheckFailedRegex); + + EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h)); + } + + // |ReadMessage()|: + // Only check arguments checked by |Core|, namely |handle|, |handles|, and + // |num_handles|. + { + MockHandleInfo info; + MojoHandle h = CreateMockHandle(&info); + + uint32_t handle_count = 1; + EXPECT_DEATH_IF_SUPPORTED( + core()->ReadMessage(h, NullUserPointer(), NullUserPointer(), + NullUserPointer(), + MakeUserPointer(&handle_count), + MOJO_READ_MESSAGE_FLAG_NONE), + kMemoryCheckFailedRegex); + + EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h)); + } +} + // TODO(vtl): test |Wait()| and |WaitMany()| properly // - including |WaitMany()| with the same handle more than once (with // same/different signals) @@ -325,7 +413,9 @@ TEST_F(CoreTest, InvalidArguments) { TEST_F(CoreTest, MessagePipe) { MojoHandle h[2]; - EXPECT_EQ(MOJO_RESULT_OK, core()->CreateMessagePipe(NULL, &h[0], &h[1])); + EXPECT_EQ(MOJO_RESULT_OK, + core()->CreateMessagePipe(NullUserPointer(), MakeUserPointer(&h[0]), + MakeUserPointer(&h[1]))); // Should get two distinct, valid handles. EXPECT_NE(h[0], MOJO_HANDLE_INVALID); EXPECT_NE(h[1], MOJO_HANDLE_INVALID); @@ -335,13 +425,16 @@ TEST_F(CoreTest, MessagePipe) { MojoHandleSignals signals[2] = {MOJO_HANDLE_SIGNAL_READABLE, MOJO_HANDLE_SIGNAL_READABLE}; EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, - core()->WaitMany(h, signals, 2, 0)); + core()->WaitMany(MakeUserPointer(h), MakeUserPointer(signals), 2, + 0)); // Try to read anyway. char buffer[1] = {'a'}; uint32_t buffer_size = 1; EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT, - core()->ReadMessage(h[0], buffer, &buffer_size, NULL, NULL, + core()->ReadMessage(h[0], UserPointer<void>(buffer), + MakeUserPointer(&buffer_size), + NullUserPointer(), NullUserPointer(), MOJO_READ_MESSAGE_FLAG_NONE)); // Check that it left its inputs alone. EXPECT_EQ('a', buffer[0]); @@ -356,31 +449,38 @@ TEST_F(CoreTest, MessagePipe) { // Also check that |h[1]| is writable using |WaitMany()|. signals[0] = MOJO_HANDLE_SIGNAL_READABLE; signals[1] = MOJO_HANDLE_SIGNAL_WRITABLE; - EXPECT_EQ(1, core()->WaitMany(h, signals, 2, MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(1, core()->WaitMany(MakeUserPointer(h), MakeUserPointer(signals), 2, + MOJO_DEADLINE_INDEFINITE)); // Write to |h[1]|. buffer[0] = 'b'; EXPECT_EQ(MOJO_RESULT_OK, - core()->WriteMessage(h[1], buffer, 1, NULL, 0, + core()->WriteMessage(h[1], UserPointer<const void>(buffer), 1, + NullUserPointer(), 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); // Check that |h[0]| is now readable. signals[0] = MOJO_HANDLE_SIGNAL_READABLE; signals[1] = MOJO_HANDLE_SIGNAL_READABLE; - EXPECT_EQ(0, core()->WaitMany(h, signals, 2, MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(0, core()->WaitMany(MakeUserPointer(h), MakeUserPointer(signals), 2, + MOJO_DEADLINE_INDEFINITE)); // Read from |h[0]|. // First, get only the size. buffer_size = 0; EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED, - core()->ReadMessage(h[0], NULL, &buffer_size, NULL, NULL, + core()->ReadMessage(h[0], NullUserPointer(), + MakeUserPointer(&buffer_size), + NullUserPointer(), NullUserPointer(), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(1u, buffer_size); // Then actually read it. buffer[0] = 'c'; buffer_size = 1; EXPECT_EQ(MOJO_RESULT_OK, - core()->ReadMessage(h[0], buffer, &buffer_size, NULL, NULL, + core()->ReadMessage(h[0], UserPointer<void>(buffer), + MakeUserPointer(&buffer_size), + NullUserPointer(), NullUserPointer(), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ('b', buffer[0]); EXPECT_EQ(1u, buffer_size); @@ -392,7 +492,8 @@ TEST_F(CoreTest, MessagePipe) { // Write to |h[0]|. buffer[0] = 'd'; EXPECT_EQ(MOJO_RESULT_OK, - core()->WriteMessage(h[0], buffer, 1, NULL, 0, + core()->WriteMessage(h[0], UserPointer<const void>(buffer), 1, + NullUserPointer(), 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); // Close |h[0]|. @@ -408,7 +509,8 @@ TEST_F(CoreTest, MessagePipe) { // Discard a message from |h[1]|. EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED, - core()->ReadMessage(h[1], NULL, NULL, NULL, NULL, + core()->ReadMessage(h[1], NullUserPointer(), NullUserPointer(), + NullUserPointer(), NullUserPointer(), MOJO_READ_MESSAGE_FLAG_MAY_DISCARD)); // |h[1]| is no longer readable (and will never be). @@ -418,7 +520,8 @@ TEST_F(CoreTest, MessagePipe) { // Try writing to |h[1]|. buffer[0] = 'e'; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - core()->WriteMessage(h[1], buffer, 1, NULL, 0, + core()->WriteMessage(h[1], UserPointer<const void>(buffer), 1, + NullUserPointer(), 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h[1])); @@ -439,13 +542,14 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) { MojoHandle h_passing[2]; EXPECT_EQ(MOJO_RESULT_OK, - core()->CreateMessagePipe(NULL, &h_passing[0], &h_passing[1])); + core()->CreateMessagePipe(NullUserPointer(), + MakeUserPointer(&h_passing[0]), + MakeUserPointer(&h_passing[1]))); // Make sure that |h_passing[]| work properly. EXPECT_EQ(MOJO_RESULT_OK, - core()->WriteMessage(h_passing[0], - kHello, kHelloSize, - NULL, 0, + core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello), + kHelloSize, NullUserPointer(), 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE, @@ -453,9 +557,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) { num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, - core()->ReadMessage(h_passing[1], - buffer, &num_bytes, - handles, &num_handles, + core()->ReadMessage(h_passing[1], UserPointer<void>(buffer), + MakeUserPointer(&num_bytes), + MakeUserPointer(handles), + MakeUserPointer(&num_handles), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kHelloSize, num_bytes); EXPECT_STREQ(kHello, buffer); @@ -464,34 +569,34 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) { // Make sure that you can't pass either of the message pipe's handles over // itself. EXPECT_EQ(MOJO_RESULT_BUSY, - core()->WriteMessage(h_passing[0], - kHello, kHelloSize, - &h_passing[0], 1, + core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello), + kHelloSize, MakeUserPointer(&h_passing[0]), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->WriteMessage(h_passing[0], - kHello, kHelloSize, - &h_passing[1], 1, + core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello), + kHelloSize, MakeUserPointer(&h_passing[1]), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); MojoHandle h_passed[2]; EXPECT_EQ(MOJO_RESULT_OK, - core()->CreateMessagePipe(NULL, &h_passed[0], &h_passed[1])); + core()->CreateMessagePipe(NullUserPointer(), + MakeUserPointer(&h_passed[0]), + MakeUserPointer(&h_passed[1]))); // Make sure that |h_passed[]| work properly. EXPECT_EQ(MOJO_RESULT_OK, - core()->WriteMessage(h_passed[0], - kHello, kHelloSize, - NULL, 0, + core()->WriteMessage(h_passed[0], UserPointer<const void>(kHello), + kHelloSize, NullUserPointer(), 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h_passed[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000)); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, - core()->ReadMessage(h_passed[1], - buffer, &num_bytes, - handles, &num_handles, + core()->ReadMessage(h_passed[1], UserPointer<void>(buffer), + MakeUserPointer(&num_bytes), + MakeUserPointer(handles), + MakeUserPointer(&num_handles), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kHelloSize, num_bytes); EXPECT_STREQ(kHello, buffer); @@ -499,9 +604,9 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) { // Send |h_passed[1]| from |h_passing[0]| to |h_passing[1]|. EXPECT_EQ(MOJO_RESULT_OK, - core()->WriteMessage(h_passing[0], - kWorld, kWorldSize, - &h_passed[1], 1, + core()->WriteMessage(h_passing[0], UserPointer<const void>(kWorld), + kWorldSize, + MakeUserPointer(&h_passed[1]), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE, @@ -509,9 +614,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) { num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, - core()->ReadMessage(h_passing[1], - buffer, &num_bytes, - handles, &num_handles, + core()->ReadMessage(h_passing[1], UserPointer<void>(buffer), + MakeUserPointer(&num_bytes), + MakeUserPointer(handles), + MakeUserPointer(&num_handles), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kWorldSize, num_bytes); EXPECT_STREQ(kWorld, buffer); @@ -531,18 +637,18 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) { // Write to |h_passed[0]|. Should receive on |h_received|. EXPECT_EQ(MOJO_RESULT_OK, - core()->WriteMessage(h_passed[0], - kHello, kHelloSize, - NULL, 0, + core()->WriteMessage(h_passed[0], UserPointer<const void>(kHello), + kHelloSize, NullUserPointer(), 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000)); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, - core()->ReadMessage(h_received, - buffer, &num_bytes, - handles, &num_handles, + core()->ReadMessage(h_received, UserPointer<void>(buffer), + MakeUserPointer(&num_bytes), + MakeUserPointer(handles), + MakeUserPointer(&num_handles), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kHelloSize, num_bytes); EXPECT_STREQ(kHello, buffer); @@ -557,7 +663,9 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) { TEST_F(CoreTest, DataPipe) { MojoHandle ph, ch; // p is for producer and c is for consumer. - EXPECT_EQ(MOJO_RESULT_OK, core()->CreateDataPipe(NULL, &ph, &ch)); + EXPECT_EQ(MOJO_RESULT_OK, + core()->CreateDataPipe(NullUserPointer(), MakeUserPointer(&ph), + MakeUserPointer(&ch))); // Should get two distinct, valid handles. EXPECT_NE(ph, MOJO_HANDLE_INVALID); EXPECT_NE(ch, MOJO_HANDLE_INVALID); @@ -579,7 +687,8 @@ TEST_F(CoreTest, DataPipe) { char elements[2] = {'A', 'B'}; uint32_t num_bytes = 2u; EXPECT_EQ(MOJO_RESULT_OK, - core()->WriteData(ph, elements, &num_bytes, + core()->WriteData(ph, UserPointer<const void>(elements), + MakeUserPointer(&num_bytes), MOJO_WRITE_DATA_FLAG_NONE)); EXPECT_EQ(2u, num_bytes); @@ -592,7 +701,8 @@ TEST_F(CoreTest, DataPipe) { elements[1] = -1; num_bytes = 1u; EXPECT_EQ(MOJO_RESULT_OK, - core()->ReadData(ch, elements, &num_bytes, + core()->ReadData(ch, UserPointer<void>(elements), + MakeUserPointer(&num_bytes), MOJO_READ_DATA_FLAG_NONE)); EXPECT_EQ('A', elements[0]); EXPECT_EQ(-1, elements[1]); @@ -601,7 +711,8 @@ TEST_F(CoreTest, DataPipe) { void* write_ptr = NULL; num_bytes = 0u; ASSERT_EQ(MOJO_RESULT_OK, - core()->BeginWriteData(ph, &write_ptr, &num_bytes, + core()->BeginWriteData(ph, MakeUserPointer(&write_ptr), + MakeUserPointer(&num_bytes), MOJO_WRITE_DATA_FLAG_NONE)); // We count on the default options providing a decent buffer size. ASSERT_GE(num_bytes, 3u); @@ -610,7 +721,8 @@ TEST_F(CoreTest, DataPipe) { elements[0] = 'X'; num_bytes = 1u; EXPECT_EQ(MOJO_RESULT_BUSY, - core()->WriteData(ph, elements, &num_bytes, + core()->WriteData(ph, UserPointer<const void>(elements), + MakeUserPointer(&num_bytes), MOJO_WRITE_DATA_FLAG_NONE)); // Actually write the data, and complete it now. @@ -622,20 +734,21 @@ TEST_F(CoreTest, DataPipe) { // Query how much data we have. num_bytes = 0; EXPECT_EQ(MOJO_RESULT_OK, - core()->ReadData(ch, NULL, &num_bytes, MOJO_READ_DATA_FLAG_QUERY)); + core()->ReadData(ch, NullUserPointer(), MakeUserPointer(&num_bytes), + MOJO_READ_DATA_FLAG_QUERY)); EXPECT_EQ(4u, num_bytes); // Try to discard ten characters, in all-or-none mode. Should fail. num_bytes = 10; EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, - core()->ReadData(ch, NULL, &num_bytes, + core()->ReadData(ch, NullUserPointer(), MakeUserPointer(&num_bytes), MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_ALL_OR_NONE)); // Discard two characters. num_bytes = 2; EXPECT_EQ(MOJO_RESULT_OK, - core()->ReadData(ch, NULL, &num_bytes, + core()->ReadData(ch, NullUserPointer(), MakeUserPointer(&num_bytes), MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_ALL_OR_NONE)); @@ -643,7 +756,8 @@ TEST_F(CoreTest, DataPipe) { const void* read_ptr = NULL; num_bytes = 2; ASSERT_EQ(MOJO_RESULT_OK, - core()->BeginReadData(ch, &read_ptr, &num_bytes, + core()->BeginReadData(ch, MakeUserPointer(&read_ptr), + MakeUserPointer(&num_bytes), MOJO_READ_DATA_FLAG_ALL_OR_NONE)); // Note: Count on still being able to do the contiguous read here. ASSERT_EQ(2u, num_bytes); @@ -651,7 +765,7 @@ TEST_F(CoreTest, DataPipe) { // Discarding right now should fail. num_bytes = 1; EXPECT_EQ(MOJO_RESULT_BUSY, - core()->ReadData(ch, NULL, &num_bytes, + core()->ReadData(ch, NullUserPointer(), MakeUserPointer(&num_bytes), MOJO_READ_DATA_FLAG_DISCARD)); // Actually check our data and end the two-phase read. @@ -689,17 +803,19 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) { MojoHandle h_passing[2]; EXPECT_EQ(MOJO_RESULT_OK, - core()->CreateMessagePipe(NULL, &h_passing[0], &h_passing[1])); + core()->CreateMessagePipe(NullUserPointer(), + MakeUserPointer(&h_passing[0]), + MakeUserPointer(&h_passing[1]))); MojoHandle ph, ch; EXPECT_EQ(MOJO_RESULT_OK, - core()->CreateDataPipe(NULL, &ph, &ch)); + core()->CreateDataPipe(NullUserPointer(), MakeUserPointer(&ph), + MakeUserPointer(&ch))); // Send |ch| from |h_passing[0]| to |h_passing[1]|. EXPECT_EQ(MOJO_RESULT_OK, - core()->WriteMessage(h_passing[0], - kHello, kHelloSize, - &ch, 1, + core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello), + kHelloSize, MakeUserPointer(&ch), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE, @@ -707,9 +823,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) { num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, - core()->ReadMessage(h_passing[1], - buffer, &num_bytes, - handles, &num_handles, + core()->ReadMessage(h_passing[1], UserPointer<void>(buffer), + MakeUserPointer(&num_bytes), + MakeUserPointer(handles), + MakeUserPointer(&num_handles), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kHelloSize, num_bytes); EXPECT_STREQ(kHello, buffer); @@ -730,22 +847,23 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) { // Write to |ph|. Should receive on |ch_received|. num_bytes = kWorldSize; EXPECT_EQ(MOJO_RESULT_OK, - core()->WriteData(ph, kWorld, &num_bytes, + core()->WriteData(ph, UserPointer<const void>(kWorld), + MakeUserPointer(&num_bytes), MOJO_WRITE_DATA_FLAG_ALL_OR_NONE)); EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(ch_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000)); num_bytes = kBufferSize; EXPECT_EQ(MOJO_RESULT_OK, - core()->ReadData(ch_received, buffer, &num_bytes, + core()->ReadData(ch_received, UserPointer<void>(buffer), + MakeUserPointer(&num_bytes), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kWorldSize, num_bytes); EXPECT_STREQ(kWorld, buffer); // Now pass |ph| in the same direction. EXPECT_EQ(MOJO_RESULT_OK, - core()->WriteMessage(h_passing[0], - kWorld, kWorldSize, - &ph, 1, + core()->WriteMessage(h_passing[0], UserPointer<const void>(kWorld), + kWorldSize, MakeUserPointer(&ph), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE, @@ -753,9 +871,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) { num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, - core()->ReadMessage(h_passing[1], - buffer, &num_bytes, - handles, &num_handles, + core()->ReadMessage(h_passing[1], UserPointer<void>(buffer), + MakeUserPointer(&num_bytes), + MakeUserPointer(handles), + MakeUserPointer(&num_handles), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kWorldSize, num_bytes); EXPECT_STREQ(kWorld, buffer); @@ -776,13 +895,15 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) { // Write to |ph_received|. Should receive on |ch_received|. num_bytes = kHelloSize; EXPECT_EQ(MOJO_RESULT_OK, - core()->WriteData(ph_received, kHello, &num_bytes, + core()->WriteData(ph_received, UserPointer<const void>(kHello), + MakeUserPointer(&num_bytes), MOJO_WRITE_DATA_FLAG_ALL_OR_NONE)); EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(ch_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000)); num_bytes = kBufferSize; EXPECT_EQ(MOJO_RESULT_OK, - core()->ReadData(ch_received, buffer, &num_bytes, + core()->ReadData(ch_received, UserPointer<void>(buffer), + MakeUserPointer(&num_bytes), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kHelloSize, num_bytes); EXPECT_STREQ(kHello, buffer); @@ -796,20 +917,19 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) { void* write_ptr = NULL; num_bytes = 0; ASSERT_EQ(MOJO_RESULT_OK, - core()->BeginWriteData(ph, &write_ptr, &num_bytes, + core()->BeginWriteData(ph, MakeUserPointer(&write_ptr), + MakeUserPointer(&num_bytes), MOJO_WRITE_DATA_FLAG_NONE)); ASSERT_GE(num_bytes, 1u); EXPECT_EQ(MOJO_RESULT_BUSY, - core()->WriteMessage(h_passing[0], - kHello, kHelloSize, - &ph, 1, + core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello), + kHelloSize, MakeUserPointer(&ph), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); // But |ch| can, even if |ph| is in a two-phase write. EXPECT_EQ(MOJO_RESULT_OK, - core()->WriteMessage(h_passing[0], - kHello, kHelloSize, - &ch, 1, + core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello), + kHelloSize, MakeUserPointer(&ch), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); ch = MOJO_HANDLE_INVALID; EXPECT_EQ(MOJO_RESULT_OK, @@ -818,9 +938,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) { num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, - core()->ReadMessage(h_passing[1], - buffer, &num_bytes, - handles, &num_handles, + core()->ReadMessage(h_passing[1], UserPointer<void>(buffer), + MakeUserPointer(&num_bytes), + MakeUserPointer(handles), + MakeUserPointer(&num_handles), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kHelloSize, num_bytes); EXPECT_STREQ(kHello, buffer); @@ -840,19 +961,18 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) { const void* read_ptr = NULL; num_bytes = 1; ASSERT_EQ(MOJO_RESULT_OK, - core()->BeginReadData(ch, &read_ptr, &num_bytes, + core()->BeginReadData(ch, MakeUserPointer(&read_ptr), + MakeUserPointer(&num_bytes), MOJO_READ_DATA_FLAG_ALL_OR_NONE)); EXPECT_EQ(MOJO_RESULT_BUSY, - core()->WriteMessage(h_passing[0], - kHello, kHelloSize, - &ch, 1, + core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello), + kHelloSize, MakeUserPointer(&ch), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); // But |ph| can, even if |ch| is in a two-phase read. EXPECT_EQ(MOJO_RESULT_OK, - core()->WriteMessage(h_passing[0], - kWorld, kWorldSize, - &ph, 1, + core()->WriteMessage(h_passing[0], UserPointer<const void>(kWorld), + kWorldSize, MakeUserPointer(&ph), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); ph = MOJO_HANDLE_INVALID; EXPECT_EQ(MOJO_RESULT_OK, @@ -861,9 +981,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) { num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, - core()->ReadMessage(h_passing[1], - buffer, &num_bytes, - handles, &num_handles, + core()->ReadMessage(h_passing[1], UserPointer<void>(buffer), + MakeUserPointer(&num_bytes), + MakeUserPointer(handles), + MakeUserPointer(&num_handles), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kWorldSize, num_bytes); EXPECT_STREQ(kWorld, buffer); diff --git a/mojo/system/entrypoints.cc b/mojo/system/entrypoints.cc index b70fcad..2ee2c3e 100644 --- a/mojo/system/entrypoints.cc +++ b/mojo/system/entrypoints.cc @@ -12,6 +12,9 @@ static mojo::system::Core* g_core = NULL; +using mojo::system::MakeUserPointer; +using mojo::system::MakeUserPointerValue; + namespace mojo { namespace system { namespace entrypoints { @@ -49,14 +52,18 @@ MojoResult MojoWaitMany(const MojoHandle* handles, const MojoHandleSignals* signals, uint32_t num_handles, MojoDeadline deadline) { - return g_core->WaitMany(handles, signals, num_handles, deadline); + return g_core->WaitMany(MakeUserPointer(handles), + MakeUserPointer(signals), + num_handles, + deadline); } MojoResult MojoCreateMessagePipe(const MojoCreateMessagePipeOptions* options, MojoHandle* message_pipe_handle0, MojoHandle* message_pipe_handle1) { - return g_core->CreateMessagePipe( - options, message_pipe_handle0, message_pipe_handle1); + return g_core->CreateMessagePipe(MakeUserPointer(options), + MakeUserPointer(message_pipe_handle0), + MakeUserPointer(message_pipe_handle1)); } MojoResult MojoWriteMessage(MojoHandle message_pipe_handle, @@ -65,41 +72,54 @@ MojoResult MojoWriteMessage(MojoHandle message_pipe_handle, const MojoHandle* handles, uint32_t num_handles, MojoWriteMessageFlags flags) { - return g_core->WriteMessage( - message_pipe_handle, bytes, num_bytes, handles, num_handles, flags); + return g_core->WriteMessage(message_pipe_handle, + MakeUserPointer(bytes), + num_bytes, + MakeUserPointer(handles), + num_handles, + flags); } MojoResult MojoReadMessage(MojoHandle message_pipe_handle, void* bytes, uint32_t* num_bytes, MojoHandle* handles, - uint32_t* num_handles, + uint32_t* num_handles, MojoReadMessageFlags flags) { - return g_core->ReadMessage( - message_pipe_handle, bytes, num_bytes, handles, num_handles, flags); + return g_core->ReadMessage(message_pipe_handle, + MakeUserPointer(bytes), + MakeUserPointer(num_bytes), + MakeUserPointer(handles), + MakeUserPointer(num_handles), + flags); } MojoResult MojoCreateDataPipe(const MojoCreateDataPipeOptions* options, MojoHandle* data_pipe_producer_handle, MojoHandle* data_pipe_consumer_handle) { - return g_core->CreateDataPipe( - options, data_pipe_producer_handle, data_pipe_consumer_handle); + return g_core->CreateDataPipe(MakeUserPointer(options), + MakeUserPointer(data_pipe_producer_handle), + MakeUserPointer(data_pipe_consumer_handle)); } MojoResult MojoWriteData(MojoHandle data_pipe_producer_handle, const void* elements, uint32_t* num_elements, MojoWriteDataFlags flags) { - return g_core->WriteData( - data_pipe_producer_handle, elements, num_elements, flags); + return g_core->WriteData(data_pipe_producer_handle, + MakeUserPointer(elements), + MakeUserPointer(num_elements), + flags); } MojoResult MojoBeginWriteData(MojoHandle data_pipe_producer_handle, void** buffer, uint32_t* buffer_num_elements, MojoWriteDataFlags flags) { - return g_core->BeginWriteData( - data_pipe_producer_handle, buffer, buffer_num_elements, flags); + return g_core->BeginWriteData(data_pipe_producer_handle, + MakeUserPointer(buffer), + MakeUserPointer(buffer_num_elements), + flags); } MojoResult MojoEndWriteData(MojoHandle data_pipe_producer_handle, @@ -111,16 +131,20 @@ MojoResult MojoReadData(MojoHandle data_pipe_consumer_handle, void* elements, uint32_t* num_elements, MojoReadDataFlags flags) { - return g_core->ReadData( - data_pipe_consumer_handle, elements, num_elements, flags); + return g_core->ReadData(data_pipe_consumer_handle, + MakeUserPointer(elements), + MakeUserPointer(num_elements), + flags); } MojoResult MojoBeginReadData(MojoHandle data_pipe_consumer_handle, const void** buffer, uint32_t* buffer_num_elements, MojoReadDataFlags flags) { - return g_core->BeginReadData( - data_pipe_consumer_handle, buffer, buffer_num_elements, flags); + return g_core->BeginReadData(data_pipe_consumer_handle, + MakeUserPointer(buffer), + MakeUserPointer(buffer_num_elements), + flags); } MojoResult MojoEndReadData(MojoHandle data_pipe_consumer_handle, @@ -132,15 +156,18 @@ MojoResult MojoCreateSharedBuffer( const struct MojoCreateSharedBufferOptions* options, uint64_t num_bytes, MojoHandle* shared_buffer_handle) { - return g_core->CreateSharedBuffer(options, num_bytes, shared_buffer_handle); + return g_core->CreateSharedBuffer(MakeUserPointer(options), + num_bytes, + MakeUserPointer(shared_buffer_handle)); } MojoResult MojoDuplicateBufferHandle( MojoHandle buffer_handle, const struct MojoDuplicateBufferHandleOptions* options, MojoHandle* new_buffer_handle) { - return g_core->DuplicateBufferHandle( - buffer_handle, options, new_buffer_handle); + return g_core->DuplicateBufferHandle(buffer_handle, + MakeUserPointer(options), + MakeUserPointer(new_buffer_handle)); } MojoResult MojoMapBuffer(MojoHandle buffer_handle, @@ -148,11 +175,15 @@ MojoResult MojoMapBuffer(MojoHandle buffer_handle, uint64_t num_bytes, void** buffer, MojoMapBufferFlags flags) { - return g_core->MapBuffer(buffer_handle, offset, num_bytes, buffer, flags); + return g_core->MapBuffer(buffer_handle, + offset, + num_bytes, + MakeUserPointer(buffer), + flags); } MojoResult MojoUnmapBuffer(void* buffer) { - return g_core->UnmapBuffer(buffer); + return g_core->UnmapBuffer(MakeUserPointerValue(buffer)); } } // extern "C" diff --git a/mojo/system/mapping_table.cc b/mojo/system/mapping_table.cc index a6e5bb3..6170679 100644 --- a/mojo/system/mapping_table.cc +++ b/mojo/system/mapping_table.cc @@ -33,9 +33,8 @@ MojoResult MappingTable::AddMapping( return MOJO_RESULT_OK; } -MojoResult MappingTable::RemoveMapping(void* address) { - AddressToMappingMap::iterator it = - address_to_mapping_map_.find(reinterpret_cast<uintptr_t>(address)); +MojoResult MappingTable::RemoveMapping(uintptr_t address) { + AddressToMappingMap::iterator it = address_to_mapping_map_.find(address); if (it == address_to_mapping_map_.end()) return MOJO_RESULT_INVALID_ARGUMENT; RawSharedBufferMapping* mapping_to_delete = it->second; diff --git a/mojo/system/mapping_table.h b/mojo/system/mapping_table.h index 5268234..e21d685 100644 --- a/mojo/system/mapping_table.h +++ b/mojo/system/mapping_table.h @@ -39,7 +39,7 @@ class MOJO_SYSTEM_IMPL_EXPORT MappingTable { // Tries to add a mapping. (Takes ownership of the mapping in all cases; on // failure, it will be destroyed.) MojoResult AddMapping(scoped_ptr<RawSharedBufferMapping> mapping); - MojoResult RemoveMapping(void* address); + MojoResult RemoveMapping(uintptr_t address); private: friend bool internal::ShutdownCheckNoLeaks(Core*); diff --git a/mojo/system/memory.cc b/mojo/system/memory.cc index cee7e05..160e1e5 100644 --- a/mojo/system/memory.cc +++ b/mojo/system/memory.cc @@ -29,6 +29,11 @@ bool IsAligned<8>(const void* pointer) { #endif template <size_t size, size_t alignment> +void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper(const void* pointer) { + CHECK(pointer && IsAligned<alignment>(pointer)); +} + +template <size_t size, size_t alignment> bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper(const void* pointer) { // TODO(vtl): If running in kernel mode, do a full verification. For now, just // check that it's non-null and aligned. (A faster user mode implementation is @@ -37,6 +42,12 @@ bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper(const void* pointer) { } // Explicitly instantiate the sizes we need. Add instantiations as needed. +template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper<1, 1>( + const void*); +template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper<4, 4>( + const void*); +template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper<8, 8>( + const void*); template bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper<1, 1>( const void*); template bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper<4, 4>( @@ -49,16 +60,39 @@ template bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper<8, 8>( // this in particular to check that various Options structs are aligned. #if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS) template <> +void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper<4, 8>( + const void* pointer) { + CHECK(pointer && reinterpret_cast<uintptr_t>(pointer) % 8 == 0); +} +template <> bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper<4, 8>( const void* pointer) { return !!pointer && reinterpret_cast<uintptr_t>(pointer) % 8 == 0; } #else +template MOJO_SYSTEM_IMPL_EXPORT void CheckUserPointerHelper<4, 8>( + const void*); template MOJO_SYSTEM_IMPL_EXPORT bool VerifyUserPointerHelper<4, 8>( const void*); #endif template <size_t size, size_t alignment> +void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerWithCountHelper( + const void* pointer, + size_t count) { + CHECK_LE(count, std::numeric_limits<size_t>::max() / size); + CHECK(count == 0 || (pointer && IsAligned<alignment>(pointer))); +} + +// Explicitly instantiate the sizes we need. Add instantiations as needed. +template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerWithCountHelper<1, 1>( + const void*, size_t); +template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerWithCountHelper<4, 4>( + const void*, size_t); +template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerWithCountHelper<8, 8>( + const void*, size_t); + +template <size_t size, size_t alignment> bool VerifyUserPointerWithCountHelper(const void* pointer, size_t count) { if (count > std::numeric_limits<size_t>::max() / size) return false; @@ -77,7 +111,7 @@ template bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithCountHelper<4, 4>( template bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithCountHelper<8, 8>( const void*, size_t); -} // nameespace internal +} // namespace internal template <size_t alignment> bool VerifyUserPointerWithSize(const void* pointer, size_t size) { diff --git a/mojo/system/memory.h b/mojo/system/memory.h index 96f800e..e19bfa8 100644 --- a/mojo/system/memory.h +++ b/mojo/system/memory.h @@ -6,7 +6,11 @@ #define MOJO_SYSTEM_MEMORY_H_ #include <stddef.h> +#include <stdint.h> +#include <string.h> // For |memcpy()|. +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" #include "mojo/public/c/system/macros.h" #include "mojo/system/system_impl_export.h" @@ -15,6 +19,26 @@ namespace system { namespace internal { +// Removes |const| from |T| (available as |remove_const<T>::type|): +// TODO(vtl): Remove these once we have the C++11 |remove_const|. +template <typename T> struct remove_const { typedef T type; }; +template <typename T> struct remove_const<const T> { typedef T type; }; + +// Yields |(const) char| if |T| is |(const) void|, else |T|: +template <typename T> struct VoidToChar { typedef T type; }; +template <> struct VoidToChar<void> { typedef char type; }; +template <> struct VoidToChar<const void> { typedef const char type; }; + +template <size_t size, size_t alignment> +void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper(const void* pointer); + +template <size_t size, size_t alignment> +void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerWithCountHelper( + const void* pointer, + size_t count); + +// TODO(vtl): Delete all the |Verify...()| things (and replace them with +// |Check...()|. template <size_t size, size_t alignment> bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper(const void* pointer); @@ -26,6 +50,11 @@ bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithCountHelper( } // namespace internal +// Forward declarations so that they can be friended. +template <typename Type> class UserPointerReader; +template <typename Type> class UserPointerWriter; +template <typename Type> class UserPointerReaderWriter; + // Verify (insofar as possible/necessary) that a |T| can be read from the user // |pointer|. template <typename T> @@ -50,6 +79,247 @@ template <size_t alignment> bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithSize(const void* pointer, size_t size); +// Provides a convenient way to implicitly get null |UserPointer<Type>|s. +struct NullUserPointer {}; + +// Represents a user pointer to a single |Type| (which must be POD), for Mojo +// primitive parameters. +// +// Use a const |Type| for in parameters, and non-const |Type|s for out and +// in-out parameters (in which case the |Put()| method is available). +template <typename Type> +class UserPointer { + public: + // Instead of explicitly using these constructors, you can often use + // |MakeUserPointer()| (or |NullUserPointer()| for null pointers). (The common + // exception is when you have, e.g., a |char*| and want to get a + // |UserPointer<void>|.) + UserPointer() : pointer_(NULL) {} + explicit UserPointer(Type* pointer) : pointer_(pointer) {} + // Allow implicit conversion from the "null user pointer". + UserPointer(NullUserPointer) : pointer_(NULL) {} + ~UserPointer() {} + + // Allow assignment from the "null user pointer". + UserPointer<Type>& operator=(NullUserPointer) { + pointer_ = NULL; + return *this; + } + + // Allow conversion to a "non-const" |UserPointer|. + operator UserPointer<const Type>() const { + return UserPointer<const Type>(pointer_); + } + + bool IsNull() const { + return !pointer_; + } + + // We want to force a copy here, so return |Type| not |const Type&|. + Type Get() const { + internal::CheckUserPointerHelper<sizeof(Type), + MOJO_ALIGNOF(Type)>(pointer_); + return *pointer_; + } + + // Note: This |Put()| method is not valid when |T| is const, e.g., |const + // uint32_t|, but it's okay to include them so long as this template is only + // implicitly instantiated (see 14.7.1 of the C++11 standard) and not + // explicitly instantiated. (On implicit instantiation, only the declarations + // need be valid, not the definitions.) + // + // If |Type| is |void|, we "convert" it to |char|, so that it makes sense. + // (Otherwise, we'd need a suitable specialization to exclude |Put()|.) + // + // In C++11, we could do something like: + // template <typename _Type = Type> + // typename enable_if<!is_const<_Type>::value && + // !is_void<_Type>::value>::type Put( + // const _Type& value) { ... } + // (which obviously be correct), but C++03 doesn't allow default function + // template arguments. + void Put(const typename internal::VoidToChar<Type>::type& value) { + internal::CheckUserPointerHelper<sizeof(Type), + MOJO_ALIGNOF(Type)>(pointer_); + *pointer_ = value; + } + + UserPointer At(size_t i) const { + return UserPointer(pointer_ + i); + } + + // TODO(vtl): This is temporary. Get rid of this. (We should pass + // |UserPointer<>|s along appropriately, or access data in a safe way + // everywhere.) + Type* GetPointerUnsafe() const { + return pointer_; + } + + // These provides safe (read-only/write-only/read-and-write) access to a + // |UserPointer<Type>| (probably pointing to an array) using just an ordinary + // pointer (obtained via |GetPointer()|). + // + // The memory returned by |GetPointer()| may be a copy of the original user + // memory, but should be modified only if the user is intended to eventually + // see the change.) If any changes are made, |Commit()| should be called to + // guarantee that the changes are written back to user memory (it may be + // called multiple times). + // + // Note: These classes are designed to allow fast, unsafe implementations (in + // which |GetPointer()| just returns the user pointer) if desired. Thus if + // |Commit()| is *not* called, changes may or may not be made visible to the + // user. + // + // Use these classes in the following way: + // + // MojoResult Core::PutFoos(UserPointer<const uint32_t> foos, + // uint32_t num_foos) { + // UserPointer<const uint32_t>::Reader foos_reader(foos, num_foos); + // return PutFoosImpl(foos_reader.GetPointer(), num_foos); + // } + // + // MojoResult Core::GetFoos(UserPointer<uint32_t> foos, + // uint32_t num_foos) { + // UserPointer<uint32_t>::Writer foos_writer(foos, num_foos); + // MojoResult rv = GetFoosImpl(foos.GetPointer(), num_foos); + // foos_writer.Commit(); + // return rv; + // } + // + // TODO(vtl): Possibly, since we're not really being safe, we should just not + // copy for Release builds. + typedef UserPointerReader<Type> Reader; + typedef UserPointerWriter<Type> Writer; + typedef UserPointerReaderWriter<Type> ReaderWriter; + + private: + friend class UserPointerReader<Type>; + friend class UserPointerWriter<Type>; + friend class UserPointerReaderWriter<Type>; + + Type* pointer_; + // Allow copy and assignment. +}; + +// Provides a convenient way to make a |UserPointer<Type>|. +template <typename Type> +inline UserPointer<Type> MakeUserPointer(Type* pointer) { + return UserPointer<Type>(pointer); +} + +// Implementation of |UserPointer<Type>::Reader|. +template <typename Type> +class UserPointerReader { + private: + typedef typename internal::remove_const<Type>::type TypeNoConst; + + public: + UserPointerReader(UserPointer<const Type> user_pointer, size_t count) { + Init(user_pointer.pointer_, count); + } + UserPointerReader(UserPointer<TypeNoConst> user_pointer, size_t count) { + Init(user_pointer.pointer_, count); + } + + const Type* GetPointer() const { return buffer_.get(); } + + private: + void Init(const Type* user_pointer, size_t count) { + internal::CheckUserPointerWithCountHelper< + sizeof(Type), MOJO_ALIGNOF(Type)>(user_pointer, count); + buffer_.reset(new TypeNoConst[count]); + memcpy(buffer_.get(), user_pointer, count * sizeof(Type)); + } + + scoped_ptr<TypeNoConst[]> buffer_; + + DISALLOW_COPY_AND_ASSIGN(UserPointerReader); +}; + +// Implementation of |UserPointer<Type>::Writer|. +template <typename Type> +class UserPointerWriter { + public: + UserPointerWriter(UserPointer<Type> user_pointer, size_t count) + : user_pointer_(user_pointer), + count_(count) { + buffer_.reset(new Type[count_]); + memset(buffer_.get(), 0, count_ * sizeof(Type)); + } + + Type* GetPointer() const { return buffer_.get(); } + + void Commit() { + internal::CheckUserPointerWithCountHelper< + sizeof(Type), MOJO_ALIGNOF(Type)>(user_pointer_.pointer_, count_); + memcpy(user_pointer_.pointer_, buffer_.get(), count_ * sizeof(Type)); + } + + private: + UserPointer<Type> user_pointer_; + size_t count_; + scoped_ptr<Type[]> buffer_; + + DISALLOW_COPY_AND_ASSIGN(UserPointerWriter); +}; + +// Implementation of |UserPointer<Type>::ReaderWriter|. +template <typename Type> +class UserPointerReaderWriter { + public: + UserPointerReaderWriter(UserPointer<Type> user_pointer, size_t count) + : user_pointer_(user_pointer), + count_(count) { + internal::CheckUserPointerWithCountHelper< + sizeof(Type), MOJO_ALIGNOF(Type)>(user_pointer_.pointer_, count_); + buffer_.reset(new Type[count]); + memcpy(buffer_.get(), user_pointer.pointer_, count * sizeof(Type)); + } + + Type* GetPointer() const { return buffer_.get(); } + size_t GetCount() const { return count_; } + + void Commit() { + internal::CheckUserPointerWithCountHelper< + sizeof(Type), MOJO_ALIGNOF(Type)>(user_pointer_.pointer_, count_); + memcpy(user_pointer_.pointer_, buffer_.get(), count_ * sizeof(Type)); + } + + private: + UserPointer<Type> user_pointer_; + size_t count_; + scoped_ptr<Type[]> buffer_; + + DISALLOW_COPY_AND_ASSIGN(UserPointerReaderWriter); +}; + +// Represents a user pointer that will never be dereferenced by the system. The +// pointer value (i.e., the address) may be as a key for lookup, or may be a +// value that is only passed to the user at some point. +template <typename Type> +class UserPointerValue { + public: + UserPointerValue() : pointer_() {} + explicit UserPointerValue(Type* pointer) : pointer_(pointer) {} + ~UserPointerValue() {} + + // Returns the *value* of the pointer, which shouldn't be cast back to a + // pointer and dereferenced. + uintptr_t GetValue() const { + return reinterpret_cast<uintptr_t>(pointer_); + } + + private: + Type* pointer_; + // Allow copy and assignment. +}; + +// Provides a convenient way to make a |UserPointerValue<Type>|. +template <typename Type> +inline UserPointerValue<Type> MakeUserPointerValue(Type* pointer) { + return UserPointerValue<Type>(pointer); +} + } // namespace system } // namespace mojo |